AudioAttributesImplBase.java
/*
* 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 static androidx.media.AudioAttributesCompat.CONTENT_TYPE_MOVIE;
import static androidx.media.AudioAttributesCompat.CONTENT_TYPE_MUSIC;
import static androidx.media.AudioAttributesCompat.CONTENT_TYPE_SONIFICATION;
import static androidx.media.AudioAttributesCompat.CONTENT_TYPE_SPEECH;
import static androidx.media.AudioAttributesCompat.CONTENT_TYPE_UNKNOWN;
import static androidx.media.AudioAttributesCompat.INVALID_STREAM_TYPE;
import static androidx.media.AudioAttributesCompat.TAG;
import static androidx.media.AudioAttributesCompat.USAGE_ALARM;
import static androidx.media.AudioAttributesCompat.USAGE_ASSISTANCE_ACCESSIBILITY;
import static androidx.media.AudioAttributesCompat.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
import static androidx.media.AudioAttributesCompat.USAGE_ASSISTANCE_SONIFICATION;
import static androidx.media.AudioAttributesCompat.USAGE_ASSISTANT;
import static androidx.media.AudioAttributesCompat.USAGE_GAME;
import static androidx.media.AudioAttributesCompat.USAGE_MEDIA;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION_EVENT;
import static androidx.media.AudioAttributesCompat.USAGE_NOTIFICATION_RINGTONE;
import static androidx.media.AudioAttributesCompat.USAGE_UNKNOWN;
import static androidx.media.AudioAttributesCompat.USAGE_VIRTUAL_SOURCE;
import static androidx.media.AudioAttributesCompat.USAGE_VOICE_COMMUNICATION;
import static androidx.media.AudioAttributesCompat.USAGE_VOICE_COMMUNICATION_SIGNALLING;
import android.media.AudioManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.media.AudioAttributesCompat.AudioManagerHidden;
import androidx.versionedparcelable.ParcelField;
import androidx.versionedparcelable.VersionedParcelize;
import java.util.Arrays;
/** @hide */
@VersionedParcelize(jetifyAs = "android.support.v4.media.AudioAttributesImplBase")
@RestrictTo(LIBRARY)
public class AudioAttributesImplBase implements AudioAttributesImpl {
/** @hide */
// It should be public to allow Parcelizers which never be de/jetified can access the field.
@RestrictTo(LIBRARY)
@ParcelField(1)
public int mUsage = USAGE_UNKNOWN;
/** @hide */
// It should be public to allow Parcelizers which never be de/jetified can access the field.
@RestrictTo(LIBRARY)
@ParcelField(2)
public int mContentType = CONTENT_TYPE_UNKNOWN;
/** @hide */
// It should be public to allow Parcelizers which never be de/jetified can access the field.
@RestrictTo(LIBRARY)
@ParcelField(3)
public int mFlags = 0x0;
/** @hide */
// It should be public to allow Parcelizers which never be de/jetified can access the field.
@RestrictTo(LIBRARY)
@ParcelField(4)
public int mLegacyStream = INVALID_STREAM_TYPE;
// 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 AudioAttributesImplBase() { }
AudioAttributesImplBase(int contentType, int flags, int usage, int legacyStream) {
mContentType = contentType;
mFlags = flags;
mUsage = usage;
mLegacyStream = legacyStream;
}
@Override
@Nullable
public Object getAudioAttributes() {
return null;
}
@Override
public int getVolumeControlStream() {
return AudioAttributesCompat.toVolumeStreamType(true, mFlags, mUsage);
}
@Override
public int getLegacyStreamType() {
if (mLegacyStream != INVALID_STREAM_TYPE) {
return mLegacyStream;
}
return AudioAttributesCompat.toVolumeStreamType(false, mFlags, mUsage);
}
@Override
public int getRawLegacyStreamType() {
return mLegacyStream;
}
@Override
public int getContentType() {
return mContentType;
}
@Override
public @AudioAttributesCompat.AttributeUsage int getUsage() {
return mUsage;
}
@Override
public int getFlags() {
int flags = mFlags;
int legacyStream = getLegacyStreamType();
if (legacyStream == AudioManagerHidden.STREAM_BLUETOOTH_SCO) {
flags |= AudioAttributesCompat.FLAG_SCO;
} else if (legacyStream == AudioManagerHidden.STREAM_SYSTEM_ENFORCED) {
flags |= AudioAttributesCompat.FLAG_AUDIBILITY_ENFORCED;
}
return flags & AudioAttributesCompat.FLAG_ALL_PUBLIC;
}
//////////////////////////////////////////////////////////////////////
// Override Object methods
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] {mContentType, mFlags, mUsage, mLegacyStream});
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AudioAttributesImplBase)) {
return false;
}
final AudioAttributesImplBase that = (AudioAttributesImplBase) o;
return ((mContentType == that.getContentType())
&& (mFlags == that.getFlags())
&& (mUsage == that.getUsage())
&& (mLegacyStream == that.mLegacyStream)); // query the slot directly, don't guess
}
@Override
@NonNull
public String toString() {
final StringBuilder sb = new StringBuilder("AudioAttributesCompat:");
if (mLegacyStream != INVALID_STREAM_TYPE) {
sb.append(" stream=").append(mLegacyStream);
sb.append(" derived");
}
sb.append(" usage=")
.append(AudioAttributesCompat.usageToString(mUsage))
.append(" content=")
.append(mContentType)
.append(" flags=0x")
.append(Integer.toHexString(mFlags).toUpperCase());
return sb.toString();
}
static class Builder implements AudioAttributesImpl.Builder {
private int mUsage = USAGE_UNKNOWN;
private int mContentType = CONTENT_TYPE_UNKNOWN;
private int mFlags = 0x0;
private int mLegacyStream = INVALID_STREAM_TYPE;
Builder() {
}
Builder(AudioAttributesCompat aa) {
mUsage = aa.getUsage();
mContentType = aa.getContentType();
mFlags = aa.getFlags();
mLegacyStream = aa.getRawLegacyStreamType();
}
@Override
@NonNull
public AudioAttributesImpl build() {
return new AudioAttributesImplBase(mContentType, mFlags, mUsage, mLegacyStream);
}
@Override
@NonNull
public Builder setUsage(@AudioAttributesCompat.AttributeUsage int usage) {
switch (usage) {
case USAGE_UNKNOWN:
case USAGE_MEDIA:
case USAGE_VOICE_COMMUNICATION:
case USAGE_VOICE_COMMUNICATION_SIGNALLING:
case USAGE_ALARM:
case USAGE_NOTIFICATION:
case USAGE_NOTIFICATION_RINGTONE:
case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case USAGE_NOTIFICATION_EVENT:
case USAGE_ASSISTANCE_ACCESSIBILITY:
case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
case USAGE_ASSISTANCE_SONIFICATION:
case USAGE_GAME:
case USAGE_VIRTUAL_SOURCE:
mUsage = usage;
break;
// TODO: shouldn't it be USAGE_ASSISTANT?
case USAGE_ASSISTANT:
mUsage = USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
break;
default:
mUsage = USAGE_UNKNOWN;
}
return this;
}
@Override
@NonNull
public Builder setContentType(@AudioAttributesCompat.AttributeContentType int contentType) {
switch (contentType) {
case CONTENT_TYPE_UNKNOWN:
case CONTENT_TYPE_MOVIE:
case CONTENT_TYPE_MUSIC:
case CONTENT_TYPE_SONIFICATION:
case CONTENT_TYPE_SPEECH:
mContentType = contentType;
break;
default:
mContentType = CONTENT_TYPE_UNKNOWN;
}
return this;
}
@Override
@NonNull
public Builder setFlags(int flags) {
flags &= AudioAttributesCompat.FLAG_ALL;
mFlags |= flags;
return this;
}
@Override
@NonNull
public Builder setLegacyStreamType(int streamType) {
if (streamType == AudioManagerHidden.STREAM_ACCESSIBILITY) {
throw new IllegalArgumentException(
"STREAM_ACCESSIBILITY is not a legacy stream "
+ "type that was used for audio playback");
}
mLegacyStream = streamType;
return setInternalLegacyStreamType(streamType);
}
private Builder setInternalLegacyStreamType(int streamType) {
switch (streamType) {
case AudioManager.STREAM_VOICE_CALL:
mContentType = CONTENT_TYPE_SPEECH;
break;
case AudioManagerHidden.STREAM_SYSTEM_ENFORCED:
mFlags |= AudioAttributesCompat.FLAG_AUDIBILITY_ENFORCED;
// intended fall through, attributes in common with STREAM_SYSTEM
case AudioManager.STREAM_SYSTEM:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManager.STREAM_RING:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManager.STREAM_MUSIC:
mContentType = CONTENT_TYPE_MUSIC;
break;
case AudioManager.STREAM_ALARM:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManager.STREAM_NOTIFICATION:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManagerHidden.STREAM_BLUETOOTH_SCO:
mContentType = CONTENT_TYPE_SPEECH;
mFlags |= AudioAttributesCompat.FLAG_SCO;
break;
case AudioManager.STREAM_DTMF:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManagerHidden.STREAM_TTS:
mContentType = CONTENT_TYPE_SONIFICATION;
break;
case AudioManager.STREAM_ACCESSIBILITY:
mContentType = CONTENT_TYPE_SPEECH;
break;
default:
Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributesCompat");
}
mUsage = usageForStreamType(streamType);
return this;
}
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
static int usageForStreamType(int streamType) {
switch (streamType) {
case AudioManager.STREAM_VOICE_CALL:
return USAGE_VOICE_COMMUNICATION;
case AudioManagerHidden.STREAM_SYSTEM_ENFORCED:
case AudioManager.STREAM_SYSTEM:
return USAGE_ASSISTANCE_SONIFICATION;
case AudioManager.STREAM_RING:
return USAGE_NOTIFICATION_RINGTONE;
case AudioManager.STREAM_MUSIC:
return USAGE_MEDIA;
case AudioManager.STREAM_ALARM:
return USAGE_ALARM;
case AudioManager.STREAM_NOTIFICATION:
return USAGE_NOTIFICATION;
case AudioManagerHidden.STREAM_BLUETOOTH_SCO:
return USAGE_VOICE_COMMUNICATION;
case AudioManager.STREAM_DTMF:
return USAGE_VOICE_COMMUNICATION_SIGNALLING;
case AudioManager.STREAM_ACCESSIBILITY:
return USAGE_ASSISTANCE_ACCESSIBILITY;
case AudioManagerHidden.STREAM_TTS:
default:
return USAGE_UNKNOWN;
}
}
}