diff options
| author | 2024-02-05 13:45:32 +0000 | |
|---|---|---|
| committer | 2024-02-05 14:10:37 +0000 | |
| commit | 4cac51712bfd5347710b7449cc652d9808246bec (patch) | |
| tree | ee055def8672dfd293d97aaf6fba73de1b16b536 | |
| parent | b18a2588b7f8503e5c1db12d1aa4bc20390605bd (diff) | |
Revert "Add back the older Ringtone implementation to allow flag control."
This reverts commit 549920720ffc7b29adc13041492d6116fa391077.
Bug: 323853450
Change-Id: Iceadf80ea342580c160106bf0b31588ef73406ea
| -rw-r--r-- | media/java/android/media/IRingtonePlayer.aidl | 12 | ||||
| -rw-r--r-- | media/java/android/media/LocalRingtonePlayer.java | 10 | ||||
| -rw-r--r-- | media/java/android/media/Ringtone.java | 527 | ||||
| -rw-r--r-- | media/java/android/media/RingtoneManager.java | 59 | ||||
| -rw-r--r-- | media/java/android/media/RingtoneV1.java | 614 | ||||
| -rw-r--r-- | media/java/android/media/RingtoneV2.java | 690 | ||||
| -rw-r--r-- | packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java | 8 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java | 69 |
8 files changed, 439 insertions, 1550 deletions
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl index 1e57be2c1e22..c515a399a141 100644 --- a/media/java/android/media/IRingtonePlayer.aidl +++ b/media/java/android/media/IRingtonePlayer.aidl @@ -30,20 +30,12 @@ interface IRingtonePlayer { /** Used for Ringtone.java playback */ @UnsupportedAppUsage oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); - oneway void stop(IBinder token); - boolean isPlaying(IBinder token); - - // RingtoneV1 - oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa, - float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig); - oneway void setPlaybackProperties(IBinder token, float volume, boolean looping, - boolean hapticGeneratorEnabled); - - // RingtoneV2 oneway void playRemoteRingtone(IBinder token, in Uri uri, in AudioAttributes aa, boolean useExactAudioAttributes, int enabledMedia, in @nullable VibrationEffect ve, float volume, boolean looping, boolean hapticGeneratorEnabled, in @nullable VolumeShaper.Configuration volumeShaperConfig); + oneway void stop(IBinder token); + boolean isPlaying(IBinder token); oneway void setLooping(IBinder token, boolean looping); oneway void setVolume(IBinder token, float volume); oneway void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled); diff --git a/media/java/android/media/LocalRingtonePlayer.java b/media/java/android/media/LocalRingtonePlayer.java index fe7cc3ec2af3..d0169b9e2501 100644 --- a/media/java/android/media/LocalRingtonePlayer.java +++ b/media/java/android/media/LocalRingtonePlayer.java @@ -37,7 +37,7 @@ import java.util.Objects; * @hide */ public class LocalRingtonePlayer - implements RingtoneV2.RingtonePlayer, MediaPlayer.OnCompletionListener { + implements Ringtone.RingtonePlayer, MediaPlayer.OnCompletionListener { private static final String TAG = "LocalRingtonePlayer"; // keep references on active Ringtones until stopped or completion listener called. @@ -45,7 +45,7 @@ public class LocalRingtonePlayer private final MediaPlayer mMediaPlayer; private final AudioAttributes mAudioAttributes; - private final RingtoneV2.RingtonePlayer mVibrationPlayer; + private final Ringtone.RingtonePlayer mVibrationPlayer; private final Ringtone.Injectables mInjectables; private final AudioManager mAudioManager; private final VolumeShaper mVolumeShaper; @@ -55,7 +55,7 @@ public class LocalRingtonePlayer @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator, @Nullable VolumeShaper volumeShaper, - @Nullable RingtoneV2.RingtonePlayer vibrationPlayer) { + @Nullable Ringtone.RingtonePlayer vibrationPlayer) { Objects.requireNonNull(mediaPlayer); Objects.requireNonNull(audioAttributes); Objects.requireNonNull(injectables); @@ -74,7 +74,7 @@ public class LocalRingtonePlayer * loaded in the local player. */ @Nullable - static RingtoneV2.RingtonePlayer create(@NonNull Context context, + static Ringtone.RingtonePlayer create(@NonNull Context context, @NonNull AudioManager audioManager, @NonNull Vibrator vibrator, @NonNull Uri soundUri, @NonNull AudioAttributes audioAttributes, @@ -311,7 +311,7 @@ public class LocalRingtonePlayer } /** A RingtonePlayer that only plays a VibrationEffect. */ - static class VibrationEffectPlayer implements RingtoneV2.RingtonePlayer { + static class VibrationEffectPlayer implements Ringtone.RingtonePlayer { private static final int VIBRATION_LOOP_DELAY_MS = 200; private final VibrationEffect mVibrationEffect; private final VibrationAttributes mVibrationAttributes; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index 0319f32521c1..3a6b39834851 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -25,11 +25,14 @@ import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.AssetFileDescriptor; +import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.media.audiofx.HapticGenerator; import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.Trace; import android.os.VibrationEffect; import android.os.Vibrator; @@ -40,6 +43,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -96,70 +100,68 @@ public class Ringtone { private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%' OR " + MediaColumns.MIME_TYPE + " IN ('application/ogg', 'application/x-flac')"; - // Flag-selected ringtone implementation to use. - private final ApiInterface mApiImpl; - - /** {@hide} */ - @UnsupportedAppUsage - public Ringtone(Context context, boolean allowRemote) { - mApiImpl = new RingtoneV1(context, allowRemote); - } + private final Context mContext; + private final Vibrator mVibrator; + private final AudioManager mAudioManager; + private VolumeShaper.Configuration mVolumeShaperConfig; /** - * Constructor for legacy V1 initialization paths using non-public APIs on RingtoneV1. + * Flag indicating if we're allowed to fall back to remote playback using + * {@link #mRemoteRingtoneService}. Typically this is false when we're the remote + * player and there is nobody else to delegate to. */ - private Ringtone(RingtoneV1 ringtoneV1) { - mApiImpl = ringtoneV1; - } + private final boolean mAllowRemote; + private final IRingtonePlayer mRemoteRingtoneService; + private final Injectables mInjectables; + + private final int mEnabledMedia; + + private final Uri mUri; + private String mTitle; + + private AudioAttributes mAudioAttributes; + private boolean mUseExactAudioAttributes; + private boolean mPreferBuiltinDevice; + private RingtonePlayer mActivePlayer; + // playback properties, use synchronized with mPlaybackSettingsLock + private boolean mIsLooping; + private float mVolume; + private boolean mHapticGeneratorEnabled; + private final Object mPlaybackSettingsLock = new Object(); + private final VibrationEffect mVibrationEffect; private Ringtone(Builder builder, @Ringtone.RingtoneMedia int effectiveEnabledMedia, @NonNull AudioAttributes effectiveAudioAttributes, @Nullable VibrationEffect effectiveVibrationEffect, boolean effectiveHapticGeneratorEnabled) { - mApiImpl = new RingtoneV2(builder.mContext, builder.mInjectables, builder.mAllowRemote, - effectiveEnabledMedia, builder.mUri, effectiveAudioAttributes, - builder.mUseExactAudioAttributes, builder.mVolumeShaperConfig, - builder.mPreferBuiltinDevice, builder.mInitialSoundVolume, builder.mLooping, - effectiveHapticGeneratorEnabled, effectiveVibrationEffect); - } - - /** - * Temporary V1 constructor for legacy V1 paths with audio attributes. - * @hide - */ - public static Ringtone createV1WithCustomAudioAttributes( - Context context, AudioAttributes audioAttributes, Uri uri, - VolumeShaper.Configuration volumeShaperConfig, boolean allowRemote) { - RingtoneV1 ringtoneV1 = new RingtoneV1(context, allowRemote); - ringtoneV1.setAudioAttributesField(audioAttributes); - ringtoneV1.setUri(uri, volumeShaperConfig); - ringtoneV1.reinitializeActivePlayer(); - return new Ringtone(ringtoneV1); - } - - /** - * Temporary V1 constructor for legacy V1 paths with stream type. - * @hide - */ - public static Ringtone createV1WithCustomStreamType( - Context context, int streamType, Uri uri, - VolumeShaper.Configuration volumeShaperConfig) { - RingtoneV1 ringtoneV1 = new RingtoneV1(context, /* allowRemote= */ true); - if (streamType >= 0) { - ringtoneV1.setStreamType(streamType); - } - ringtoneV1.setUri(uri, volumeShaperConfig); - if (!ringtoneV1.reinitializeActivePlayer()) { - Log.e(TAG, "Failed to open ringtone " + uri); - return null; - } - return new Ringtone(ringtoneV1); + // Context + mContext = builder.mContext; + mInjectables = builder.mInjectables; + //mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mAudioManager = mContext.getSystemService(AudioManager.class); + mRemoteRingtoneService = builder.mAllowRemote ? mAudioManager.getRingtonePlayer() : null; + mVibrator = mContext.getSystemService(Vibrator.class); + + // Local-only (not propagated to remote). + mPreferBuiltinDevice = builder.mPreferBuiltinDevice; // System-only + mAllowRemote = (mRemoteRingtoneService != null); // Always false for remote. + + // Properties potentially propagated to remote player. + mEnabledMedia = effectiveEnabledMedia; + mUri = builder.mUri; + mVolumeShaperConfig = builder.mVolumeShaperConfig; + mVolume = builder.mInitialSoundVolume; + mIsLooping = builder.mLooping; + mVibrationEffect = effectiveVibrationEffect; + mAudioAttributes = effectiveAudioAttributes; + mUseExactAudioAttributes = builder.mUseExactAudioAttributes; + mHapticGeneratorEnabled = effectiveHapticGeneratorEnabled; } /** @hide */ @RingtoneMedia public int getEnabledMedia() { - return mApiImpl.getEnabledMedia(); + return mEnabledMedia; } /** @@ -170,7 +172,15 @@ public class Ringtone { */ @Deprecated public void setStreamType(int streamType) { - mApiImpl.setStreamType(streamType); + setAudioAttributes( + getAudioAttributesForLegacyStreamType(streamType, "setStreamType()")); + } + + private AudioAttributes getAudioAttributesForLegacyStreamType(int streamType, String originOp) { + PlayerBase.deprecateStreamTypeForPlayback(streamType, "Ringtone", originOp); + return new AudioAttributes.Builder() + .setInternalLegacyStreamType(streamType) + .build(); } /** @@ -182,7 +192,7 @@ public class Ringtone { */ @Deprecated public int getStreamType() { - return mApiImpl.getStreamType(); + return AudioAttributes.toLegacyStreamType(mAudioAttributes); } /** @@ -191,7 +201,17 @@ public class Ringtone { */ public void setAudioAttributes(AudioAttributes attributes) throws IllegalArgumentException { - mApiImpl.setAudioAttributes(attributes); + // TODO: deprecate this method - it will be done with a builder. + if (attributes == null) { + throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone"); + } + mAudioAttributes = attributes; + // Setting the audio attributes requires re-initializing the player. + if (mActivePlayer != null) { + // The audio attributes have to be set before the media player is prepared. + // Re-initialize it. + reinitializeActivePlayer(); + } } /** @@ -201,19 +221,19 @@ public class Ringtone { */ @Nullable public VibrationEffect getVibrationEffect() { - return mApiImpl.getVibrationEffect(); + return mVibrationEffect; } /** @hide */ @VisibleForTesting public boolean getPreferBuiltinDevice() { - return mApiImpl.getPreferBuiltinDevice(); + return mPreferBuiltinDevice; } /** @hide */ @VisibleForTesting public VolumeShaper.Configuration getVolumeShaperConfig() { - return mApiImpl.getVolumeShaperConfig(); + return mVolumeShaperConfig; } /** @@ -223,13 +243,31 @@ public class Ringtone { */ @VisibleForTesting public boolean isLocalOnly() { - return mApiImpl.isLocalOnly(); + return !mAllowRemote; } /** @hide */ @VisibleForTesting public boolean isUsingRemotePlayer() { - return mApiImpl.isUsingRemotePlayer(); + return mActivePlayer instanceof RemoteRingtonePlayer; + } + + /** + * Finds the output device of type {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. This device is + * the one on which outgoing audio for SIM calls is played. + * + * @param audioManager the audio manage. + * @return the {@link AudioDeviceInfo} corresponding to the builtin device, or {@code null} if + * none can be found. + */ + private AudioDeviceInfo getBuiltinDevice(AudioManager audioManager) { + AudioDeviceInfo[] deviceList = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo device : deviceList) { + if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { + return device; + } + } + return null; } /** @@ -239,7 +277,84 @@ public class Ringtone { * @hide */ public boolean reinitializeActivePlayer() { - return mApiImpl.reinitializeActivePlayer(); + // Try creating a local media player, or fallback to creating a remote one. + Trace.beginSection("reinitializeActivePlayer"); + try { + if (mActivePlayer != null) { + // This would only happen if calling the deprecated setAudioAttributes after + // building the Ringtone. + stopAndReleaseActivePlayer(); + } + + boolean vibrationOnly = (mEnabledMedia & MEDIA_ALL) == MEDIA_VIBRATION; + // Vibration can come from the audio file if using haptic generator or if haptic + // channels are a possibility. + boolean maybeAudioVibration = mUri != null && mInjectables.isHapticPlaybackSupported() + && (mHapticGeneratorEnabled || !mAudioAttributes.areHapticChannelsMuted()); + + // VibrationEffect only, use the simplified player without checking for haptic channels. + if (vibrationOnly && !maybeAudioVibration && mVibrationEffect != null) { + mActivePlayer = new LocalRingtonePlayer.VibrationEffectPlayer( + mVibrationEffect, mAudioAttributes, mVibrator, mIsLooping); + return true; + } + + AudioDeviceInfo preferredDevice = + mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null; + if (mUri != null) { + mActivePlayer = LocalRingtonePlayer.create(mContext, mAudioManager, mVibrator, mUri, + mAudioAttributes, vibrationOnly, mVibrationEffect, mInjectables, + mVolumeShaperConfig, preferredDevice, mHapticGeneratorEnabled, mIsLooping, + mVolume); + } else { + // Using the remote player won't help play a null Uri. Revert straight to fallback. + // The vibration-only case was already covered above. + mActivePlayer = createFallbackRingtonePlayer(); + // Fall through to attempting remote fallback play if null. + } + + if (mActivePlayer == null && mAllowRemote) { + mActivePlayer = new RemoteRingtonePlayer(mRemoteRingtoneService, mUri, + mAudioAttributes, mUseExactAudioAttributes, mEnabledMedia, mVibrationEffect, + mVolumeShaperConfig, mHapticGeneratorEnabled, mIsLooping, mVolume); + } + + return mActivePlayer != null; + } finally { + Trace.endSection(); + } + } + + @Nullable + private LocalRingtonePlayer createFallbackRingtonePlayer() { + int ringtoneType = RingtoneManager.getDefaultType(mUri); + if (ringtoneType != -1 + && RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) == null) { + Log.w(TAG, "not playing fallback for " + mUri); + return null; + } + // Default ringtone, try fallback ringtone. + try (AssetFileDescriptor afd = mContext.getResources().openRawResourceFd( + com.android.internal.R.raw.fallbackring)) { + if (afd == null) { + Log.e(TAG, "Could not load fallback ringtone"); + return null; + } + + AudioDeviceInfo preferredDevice = + mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null; + return LocalRingtonePlayer.createForFallback(mAudioManager, mVibrator, afd, + mAudioAttributes, mVibrationEffect, mInjectables, mVolumeShaperConfig, + preferredDevice, mIsLooping, mVolume); + } catch (NotFoundException nfe) { + Log.e(TAG, "Fallback ringtone does not exist"); + return null; + } catch (IOException e) { + // As with the above messages, not including much information about the + // failure so as not to expose details of the fallback ringtone resource. + Log.e(TAG, "Exception reading fallback ringtone"); + return null; + } } /** @@ -247,7 +362,7 @@ public class Ringtone { * @hide */ public boolean hasHapticChannels() { - return mApiImpl.hasHapticChannels(); + return (mActivePlayer == null) ? false : mActivePlayer.hasHapticChannels(); } /** @@ -256,7 +371,7 @@ public class Ringtone { * {@link #setAudioAttributes(AudioAttributes)} or the default attributes if none were set. */ public AudioAttributes getAudioAttributes() { - return mApiImpl.getAudioAttributes(); + return mAudioAttributes; } /** @@ -264,7 +379,12 @@ public class Ringtone { * @param looping whether to loop or not. */ public void setLooping(boolean looping) { - mApiImpl.setLooping(looping); + synchronized (mPlaybackSettingsLock) { + mIsLooping = looping; + if (mActivePlayer != null) { + mActivePlayer.setLooping(looping); + } + } } /** @@ -272,7 +392,9 @@ public class Ringtone { * @return true if this player loops when playing. */ public boolean isLooping() { - return mApiImpl.isLooping(); + synchronized (mPlaybackSettingsLock) { + return mIsLooping; + } } /** @@ -281,7 +403,22 @@ public class Ringtone { * corresponds to no attenuation being applied. */ public void setVolume(float volume) { - mApiImpl.setVolume(volume); + // Ignore if sound not enabled. + if ((mEnabledMedia & MEDIA_SOUND) == 0) { + return; + } + if (volume < 0.0f) { + volume = 0.0f; + } else if (volume > 1.0f) { + volume = 1.0f; + } + + synchronized (mPlaybackSettingsLock) { + mVolume = volume; + if (mActivePlayer != null) { + mActivePlayer.setVolume(volume); + } + } } /** @@ -289,7 +426,9 @@ public class Ringtone { * @return a value between 0.0f and 1.0f. */ public float getVolume() { - return mApiImpl.getVolume(); + synchronized (mPlaybackSettingsLock) { + return mVolume; + } } /** @@ -300,7 +439,16 @@ public class Ringtone { * @see android.media.audiofx.HapticGenerator#isAvailable() */ public boolean setHapticGeneratorEnabled(boolean enabled) { - return mApiImpl.setHapticGeneratorEnabled(enabled); + if (!mInjectables.isHapticGeneratorAvailable()) { + return false; + } + synchronized (mPlaybackSettingsLock) { + mHapticGeneratorEnabled = enabled; + if (mActivePlayer != null) { + mActivePlayer.setHapticGeneratorEnabled(enabled); + } + } + return true; } /** @@ -308,7 +456,9 @@ public class Ringtone { * @return true if the HapticGenerator is enabled. */ public boolean isHapticGeneratorEnabled() { - return mApiImpl.isHapticGeneratorEnabled(); + synchronized (mPlaybackSettingsLock) { + return mHapticGeneratorEnabled; + } } /** @@ -318,7 +468,8 @@ public class Ringtone { * @param context A context used for querying. */ public String getTitle(Context context) { - return mApiImpl.getTitle(context); + if (mTitle != null) return mTitle; + return mTitle = getTitle(context, mUri, true /*followSettingsUri*/, mAllowRemote); } /** @@ -395,21 +546,38 @@ public class Ringtone { /** {@hide} */ @UnsupportedAppUsage public Uri getUri() { - return mApiImpl.getUri(); + return mUri; } /** * Plays the ringtone. */ public void play() { - mApiImpl.play(); + if (mActivePlayer != null) { + if (mActivePlayer.play()) { + return; + } else { + // Discard active player: play() is only meant to be called once. + stopAndReleaseActivePlayer(); + } + } + if (!playFallbackRingtone()) { + Log.w(TAG, "Neither local nor remote playback available"); + } } /** * Stops a playing ringtone. */ public void stop() { - mApiImpl.stop(); + stopAndReleaseActivePlayer(); + } + + private void stopAndReleaseActivePlayer() { + if (mActivePlayer != null) { + mActivePlayer.stopAndRelease(); + mActivePlayer = null; + } } /** @@ -418,7 +586,41 @@ public class Ringtone { * @return True if playing, false otherwise. */ public boolean isPlaying() { - return mApiImpl.isPlaying(); + if (mActivePlayer != null) { + return mActivePlayer.isPlaying(); + } else { + Log.w(TAG, "No active ringtone player"); + return false; + } + } + + /** + * Fallback during the play stage rather than initialization, typically due to an issue + * communicating with the remote player. + */ + private boolean playFallbackRingtone() { + if (mActivePlayer != null) { + Log.wtf(TAG, "Playing fallback ringtone with another active player"); + stopAndReleaseActivePlayer(); + } + int streamType = AudioAttributes.toLegacyStreamType(mAudioAttributes); + if (mAudioManager.getStreamVolume(streamType) == 0) { + // TODO: Return true? If volume is off, this is a successful play. + return false; + } + mActivePlayer = createFallbackRingtonePlayer(); + if (mActivePlayer == null) { + return false; // the create method logs if it returns null. + } else if (mActivePlayer.play()) { + return true; + } else { + stopAndReleaseActivePlayer(); + return false; + } + } + + void setTitle(String title) { + mTitle = title; } /** @@ -685,6 +887,140 @@ public class Ringtone { } /** + * Play a specific ringtone. This interface is implemented by either local (this process) or + * proxied-remote playback via AudioManager.getRingtonePlayer, so that the caller + * (Ringtone class) can just use a single player after the initial creation. + * @hide + */ + interface RingtonePlayer { + /** + * Start playing the ringtone, returning false if there was a problem that + * requires falling back to the fallback ringtone resource. + */ + boolean play(); + boolean isPlaying(); + void stopAndRelease(); + + // Mutating playback methods. + void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo); + void setLooping(boolean looping); + void setHapticGeneratorEnabled(boolean enabled); + void setVolume(float volume); + + boolean hasHapticChannels(); + } + + /** + * Remote RingtonePlayer. All operations are delegated via the IRingtonePlayer interface, which + * should ultimately be backed by a RingtoneLocalPlayer within the system services. + */ + static class RemoteRingtonePlayer implements RingtonePlayer { + private final IBinder mRemoteToken = new Binder(); + private final IRingtonePlayer mRemoteRingtoneService; + private final Uri mCanonicalUri; + private final int mEnabledMedia; + private final VibrationEffect mVibrationEffect; + private final VolumeShaper.Configuration mVolumeShaperConfig; + private final AudioAttributes mAudioAttributes; + private final boolean mUseExactAudioAttributes; + private boolean mIsLooping; + private float mVolume; + private boolean mHapticGeneratorEnabled; + + RemoteRingtonePlayer(@NonNull IRingtonePlayer remoteRingtoneService, + @NonNull Uri uri, @NonNull AudioAttributes audioAttributes, + boolean useExactAudioAttributes, + @RingtoneMedia int enabledMedia, @Nullable VibrationEffect vibrationEffect, + @Nullable VolumeShaper.Configuration volumeShaperConfig, + boolean hapticGeneratorEnabled, boolean initialIsLooping, float initialVolume) { + mRemoteRingtoneService = remoteRingtoneService; + mCanonicalUri = (uri == null) ? null : uri.getCanonicalUri(); + mAudioAttributes = audioAttributes; + mUseExactAudioAttributes = useExactAudioAttributes; + mEnabledMedia = enabledMedia; + mVibrationEffect = vibrationEffect; + mVolumeShaperConfig = volumeShaperConfig; + mHapticGeneratorEnabled = hapticGeneratorEnabled; + mIsLooping = initialIsLooping; + mVolume = initialVolume; + } + + @Override + public boolean play() { + try { + mRemoteRingtoneService.playRemoteRingtone(mRemoteToken, mCanonicalUri, + mAudioAttributes, mUseExactAudioAttributes, mEnabledMedia, mVibrationEffect, + mVolume, mIsLooping, mHapticGeneratorEnabled, mVolumeShaperConfig); + return true; + } catch (RemoteException e) { + Log.w(TAG, "Problem playing ringtone: " + e); + return false; + } + } + + @Override + public boolean isPlaying() { + try { + return mRemoteRingtoneService.isPlaying(mRemoteToken); + } catch (RemoteException e) { + Log.w(TAG, "Problem checking ringtone isPlaying: " + e); + return false; + } + } + + @Override + public void stopAndRelease() { + try { + mRemoteRingtoneService.stop(mRemoteToken); + } catch (RemoteException e) { + Log.w(TAG, "Problem stopping ringtone: " + e); + } + } + + @Override + public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) { + // un-implemented for remote (but not used outside system). + } + + @Override + public void setLooping(boolean looping) { + mIsLooping = looping; + try { + mRemoteRingtoneService.setLooping(mRemoteToken, looping); + } catch (RemoteException e) { + Log.w(TAG, "Problem setting looping: " + e); + } + } + + @Override + public void setHapticGeneratorEnabled(boolean enabled) { + mHapticGeneratorEnabled = enabled; + try { + mRemoteRingtoneService.setHapticGeneratorEnabled(mRemoteToken, enabled); + } catch (RemoteException e) { + Log.w(TAG, "Problem setting hapticGeneratorEnabled: " + e); + } + } + + @Override + public void setVolume(float volume) { + mVolume = volume; + try { + mRemoteRingtoneService.setVolume(mRemoteToken, volume); + } catch (RemoteException e) { + Log.w(TAG, "Problem setting volume: " + e); + } + } + + @Override + public boolean hasHapticChannels() { + // FIXME: support remote player, or internalize haptic channels support and remove + // entirely. + return false; + } + } + + /** * Interface for intercepting static methods and constructors, for unit testing only. * @hide */ @@ -735,47 +1071,4 @@ public class Ringtone { } } - - /** - * Interface for alternative Ringtone implementations. See the public Ringtone methods that - * delegate to these for documentation. - * @hide - */ - interface ApiInterface { - void setStreamType(int streamType); - int getStreamType(); - void setAudioAttributes(AudioAttributes attributes); - boolean getPreferBuiltinDevice(); - VolumeShaper.Configuration getVolumeShaperConfig(); - boolean isLocalOnly(); - boolean isUsingRemotePlayer(); - boolean reinitializeActivePlayer(); - boolean hasHapticChannels(); - AudioAttributes getAudioAttributes(); - void setLooping(boolean looping); - boolean isLooping(); - void setVolume(float volume); - float getVolume(); - boolean setHapticGeneratorEnabled(boolean enabled); - boolean isHapticGeneratorEnabled(); - String getTitle(Context context); - Uri getUri(); - void play(); - void stop(); - boolean isPlaying(); - // V2 future-public methods - @RingtoneMedia int getEnabledMedia(); - VibrationEffect getVibrationEffect(); - } - - /** - * Switch for using the new ringtone implementation (RingtoneV1 vs RingtoneV2). This may be - * called from both system server and app-side sdk. - * - * @hide - */ - public static boolean useRingtoneV2() { - // TODO(b/293846645): chang eto new flagging infra - return SystemProperties.getBoolean("persist.audio.ringtone.use_v2", false); - } } diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index d91c45acef3a..db0970ff7533 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -497,32 +497,13 @@ public class RingtoneManager { mPreviousRingtone.stop(); } - Ringtone ringtone; - Uri positionUri = getRingtoneUri(position); - if (Ringtone.useRingtoneV2()) { - mPreviousRingtone = new Ringtone.Builder( - mContext, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(mType)) - .setUri(positionUri) - .build(); - } else { - mPreviousRingtone = createRingtoneV1WithStreamType(mContext, positionUri, - inferStreamType(), /* volumeShaperConfig= */ null); - } + mPreviousRingtone = new Ringtone.Builder( + mContext, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(mType)) + .setUri(getRingtoneUri(position)) + .build(); return mPreviousRingtone; } - private static Ringtone createRingtoneV1WithStreamType( - final Context context, Uri ringtoneUri, int streamType, - @Nullable VolumeShaper.Configuration volumeShaperConfig) { - try { - return Ringtone.createV1WithCustomStreamType(context, streamType, ringtoneUri, - volumeShaperConfig); - } catch (Exception ex) { - Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex); - } - return null; - } - /** * Gets a {@link Uri} for the ringtone at the given position in the {@link Cursor}. * @@ -803,14 +784,9 @@ public class RingtoneManager { * @return A {@link Ringtone} for the given URI, or null. */ public static Ringtone getRingtone(final Context context, Uri ringtoneUri) { - if (Ringtone.useRingtoneV2()) { - return new Ringtone.Builder( - context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1)) - .setUri(ringtoneUri) - .build(); - } else { - return createRingtoneV1WithStreamType(context, ringtoneUri, -1, null); - } + return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1)) + .setUri(ringtoneUri) + .build(); } /** @@ -820,22 +796,11 @@ public class RingtoneManager { @Nullable VolumeShaper.Configuration volumeShaperConfig, AudioAttributes audioAttributes) { // TODO: move caller(s) away from this method: inline the builder call. - if (Ringtone.useRingtoneV2()) { - return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, audioAttributes) - .setUri(ringtoneUri) - .setVolumeShaperConfig(volumeShaperConfig) - .setUseExactAudioAttributes(true) // May be using audio-coupled via attrs - .build(); - } else { - try { - return Ringtone.createV1WithCustomAudioAttributes(context, audioAttributes, - ringtoneUri, volumeShaperConfig, /* allowRemote= */ true); - } catch (Exception ex) { - // Match broad catching of createRingtoneV1. - Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex); - return null; - } - } + return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, audioAttributes) + .setUri(ringtoneUri) + .setVolumeShaperConfig(volumeShaperConfig) + .setUseExactAudioAttributes(true) // May be using audio-coupled via attrs + .build(); } /** diff --git a/media/java/android/media/RingtoneV1.java b/media/java/android/media/RingtoneV1.java deleted file mode 100644 index 3c54d4a0d166..000000000000 --- a/media/java/android/media/RingtoneV1.java +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright (C) 2023 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 android.media; - -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources.NotFoundException; -import android.media.audiofx.HapticGenerator; -import android.net.Uri; -import android.os.Binder; -import android.os.Build; -import android.os.RemoteException; -import android.os.Trace; -import android.os.VibrationEffect; -import android.provider.MediaStore; -import android.provider.MediaStore.MediaColumns; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Hosts original Ringtone implementation, retained for flagging large builder+vibration features - * in RingtoneV2.java. This does not support new features in the V2 builder. - * - * Only modified methods are moved here. - * - * @hide - */ -class RingtoneV1 implements Ringtone.ApiInterface { - private static final String TAG = "RingtoneV1"; - private static final boolean LOGD = true; - - private static final String[] MEDIA_COLUMNS = new String[] { - MediaStore.Audio.Media._ID, - MediaStore.Audio.Media.TITLE - }; - /** Selection that limits query results to just audio files */ - private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%' OR " - + MediaColumns.MIME_TYPE + " IN ('application/ogg', 'application/x-flac')"; - - // keep references on active Ringtones until stopped or completion listener called. - private static final ArrayList<RingtoneV1> sActiveRingtones = new ArrayList<>(); - - private final Context mContext; - private final AudioManager mAudioManager; - private VolumeShaper.Configuration mVolumeShaperConfig; - private VolumeShaper mVolumeShaper; - - /** - * Flag indicating if we're allowed to fall back to remote playback using - * {@link #mRemotePlayer}. Typically this is false when we're the remote - * player and there is nobody else to delegate to. - */ - private final boolean mAllowRemote; - private final IRingtonePlayer mRemotePlayer; - private final Binder mRemoteToken; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private MediaPlayer mLocalPlayer; - private final MyOnCompletionListener mCompletionListener = new MyOnCompletionListener(); - private HapticGenerator mHapticGenerator; - - @UnsupportedAppUsage - private Uri mUri; - private String mTitle; - - private AudioAttributes mAudioAttributes = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .build(); - private boolean mPreferBuiltinDevice; - // playback properties, use synchronized with mPlaybackSettingsLock - private boolean mIsLooping = false; - private float mVolume = 1.0f; - private boolean mHapticGeneratorEnabled = false; - private final Object mPlaybackSettingsLock = new Object(); - - /** {@hide} */ - @UnsupportedAppUsage - public RingtoneV1(Context context, boolean allowRemote) { - mContext = context; - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - mAllowRemote = allowRemote; - mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null; - mRemoteToken = allowRemote ? new Binder() : null; - } - - /** - * Sets the stream type where this ringtone will be played. - * - * @param streamType The stream, see {@link AudioManager}. - * @deprecated use {@link #setAudioAttributes(AudioAttributes)} - */ - @Deprecated - public void setStreamType(int streamType) { - PlayerBase.deprecateStreamTypeForPlayback(streamType, "Ringtone", "setStreamType()"); - setAudioAttributes(new AudioAttributes.Builder() - .setInternalLegacyStreamType(streamType) - .build()); - } - - /** - * Gets the stream type where this ringtone will be played. - * - * @return The stream type, see {@link AudioManager}. - * @deprecated use of stream types is deprecated, see - * {@link #setAudioAttributes(AudioAttributes)} - */ - @Deprecated - public int getStreamType() { - return AudioAttributes.toLegacyStreamType(mAudioAttributes); - } - - /** - * Sets the {@link AudioAttributes} for this ringtone. - * @param attributes the non-null attributes characterizing this ringtone. - */ - public void setAudioAttributes(AudioAttributes attributes) - throws IllegalArgumentException { - setAudioAttributesField(attributes); - // The audio attributes have to be set before the media player is prepared. - // Re-initialize it. - setUri(mUri, mVolumeShaperConfig); - reinitializeActivePlayer(); - } - - /** - * Same as {@link #setAudioAttributes(AudioAttributes)} except this one does not create - * the media player. - * @hide - */ - public void setAudioAttributesField(@Nullable AudioAttributes attributes) { - if (attributes == null) { - throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone"); - } - mAudioAttributes = attributes; - } - - /** - * Finds the output device of type {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. This device is - * the one on which outgoing audio for SIM calls is played. - * - * @param audioManager the audio manage. - * @return the {@link AudioDeviceInfo} corresponding to the builtin device, or {@code null} if - * none can be found. - */ - private AudioDeviceInfo getBuiltinDevice(AudioManager audioManager) { - AudioDeviceInfo[] deviceList = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); - for (AudioDeviceInfo device : deviceList) { - if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { - return device; - } - } - return null; - } - - /** - * Sets the preferred device of the ringtong playback to the built-in device. - * - * @hide - */ - public boolean preferBuiltinDevice(boolean enable) { - mPreferBuiltinDevice = enable; - if (mLocalPlayer == null) { - return true; - } - return mLocalPlayer.setPreferredDevice(getBuiltinDevice(mAudioManager)); - } - - /** - * Creates a local media player for the ringtone using currently set attributes. - * @return true if media player creation succeeded or is deferred, - * false if it did not succeed and can't be tried remotely. - * @hide - */ - public boolean reinitializeActivePlayer() { - Trace.beginSection("reinitializeActivePlayer"); - if (mUri == null) { - Log.e(TAG, "Could not create media player as no URI was provided."); - return mAllowRemote && mRemotePlayer != null; - } - destroyLocalPlayer(); - // try opening uri locally before delegating to remote player - mLocalPlayer = new MediaPlayer(); - try { - mLocalPlayer.setDataSource(mContext, mUri); - mLocalPlayer.setAudioAttributes(mAudioAttributes); - mLocalPlayer.setPreferredDevice( - mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null); - synchronized (mPlaybackSettingsLock) { - applyPlaybackProperties_sync(); - } - if (mVolumeShaperConfig != null) { - mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig); - } - mLocalPlayer.prepare(); - - } catch (SecurityException | IOException e) { - destroyLocalPlayer(); - if (!mAllowRemote) { - Log.w(TAG, "Remote playback not allowed: " + e); - } - } - - if (LOGD) { - if (mLocalPlayer != null) { - Log.d(TAG, "Successfully created local player"); - } else { - Log.d(TAG, "Problem opening; delegating to remote player"); - } - } - Trace.endSection(); - return mLocalPlayer != null || (mAllowRemote && mRemotePlayer != null); - } - - /** - * Same as AudioManager.hasHapticChannels except it assumes an already created ringtone. - * If the ringtone has not been created, it will load based on URI provided at {@link #setUri} - * and if not URI has been set, it will assume no haptic channels are present. - * @hide - */ - public boolean hasHapticChannels() { - // FIXME: support remote player, or internalize haptic channels support and remove entirely. - try { - android.os.Trace.beginSection("Ringtone.hasHapticChannels"); - if (mLocalPlayer != null) { - for(MediaPlayer.TrackInfo trackInfo : mLocalPlayer.getTrackInfo()) { - if (trackInfo.hasHapticChannels()) { - return true; - } - } - } - } finally { - android.os.Trace.endSection(); - } - return false; - } - - /** - * Returns whether a local player has been created for this ringtone. - * @hide - */ - @VisibleForTesting - public boolean hasLocalPlayer() { - return mLocalPlayer != null; - } - - public @Ringtone.RingtoneMedia int getEnabledMedia() { - return Ringtone.MEDIA_SOUND; // RingtoneV2 only - } - - public VibrationEffect getVibrationEffect() { - return null; // RingtoneV2 only - } - - /** - * Returns the {@link AudioAttributes} used by this object. - * @return the {@link AudioAttributes} that were set with - * {@link #setAudioAttributes(AudioAttributes)} or the default attributes if none were set. - */ - public AudioAttributes getAudioAttributes() { - return mAudioAttributes; - } - - /** - * Sets the player to be looping or non-looping. - * @param looping whether to loop or not. - */ - public void setLooping(boolean looping) { - synchronized (mPlaybackSettingsLock) { - mIsLooping = looping; - applyPlaybackProperties_sync(); - } - } - - /** - * Returns whether the looping mode was enabled on this player. - * @return true if this player loops when playing. - */ - public boolean isLooping() { - synchronized (mPlaybackSettingsLock) { - return mIsLooping; - } - } - - /** - * Sets the volume on this player. - * @param volume a raw scalar in range 0.0 to 1.0, where 0.0 mutes this player, and 1.0 - * corresponds to no attenuation being applied. - */ - public void setVolume(float volume) { - synchronized (mPlaybackSettingsLock) { - if (volume < 0.0f) { volume = 0.0f; } - if (volume > 1.0f) { volume = 1.0f; } - mVolume = volume; - applyPlaybackProperties_sync(); - } - } - - /** - * Returns the volume scalar set on this player. - * @return a value between 0.0f and 1.0f. - */ - public float getVolume() { - synchronized (mPlaybackSettingsLock) { - return mVolume; - } - } - - /** - * Enable or disable the {@link android.media.audiofx.HapticGenerator} effect. The effect can - * only be enabled on devices that support the effect. - * - * @return true if the HapticGenerator effect is successfully enabled. Otherwise, return false. - * @see android.media.audiofx.HapticGenerator#isAvailable() - */ - public boolean setHapticGeneratorEnabled(boolean enabled) { - if (!HapticGenerator.isAvailable()) { - return false; - } - synchronized (mPlaybackSettingsLock) { - mHapticGeneratorEnabled = enabled; - applyPlaybackProperties_sync(); - } - return true; - } - - /** - * Return whether the {@link android.media.audiofx.HapticGenerator} effect is enabled or not. - * @return true if the HapticGenerator is enabled. - */ - public boolean isHapticGeneratorEnabled() { - synchronized (mPlaybackSettingsLock) { - return mHapticGeneratorEnabled; - } - } - - /** - * Must be called synchronized on mPlaybackSettingsLock - */ - private void applyPlaybackProperties_sync() { - if (mLocalPlayer != null) { - mLocalPlayer.setVolume(mVolume); - mLocalPlayer.setLooping(mIsLooping); - if (mHapticGenerator == null && mHapticGeneratorEnabled) { - mHapticGenerator = HapticGenerator.create(mLocalPlayer.getAudioSessionId()); - } - if (mHapticGenerator != null) { - mHapticGenerator.setEnabled(mHapticGeneratorEnabled); - } - } else if (mAllowRemote && (mRemotePlayer != null)) { - try { - mRemotePlayer.setPlaybackProperties( - mRemoteToken, mVolume, mIsLooping, mHapticGeneratorEnabled); - } catch (RemoteException e) { - Log.w(TAG, "Problem setting playback properties: ", e); - } - } else { - Log.w(TAG, - "Neither local nor remote player available when applying playback properties"); - } - } - - /** - * Returns a human-presentable title for ringtone. Looks in media - * content provider. If not in either, uses the filename - * - * @param context A context used for querying. - */ - public String getTitle(Context context) { - if (mTitle != null) return mTitle; - return mTitle = Ringtone.getTitle(context, mUri, true /*followSettingsUri*/, mAllowRemote); - } - - /** - * Set {@link Uri} to be used for ringtone playback. - * {@link IRingtonePlayer}. - * - * @hide - */ - @UnsupportedAppUsage - public void setUri(Uri uri) { - setUri(uri, null); - } - - /** - * @hide - */ - public void setVolumeShaperConfig(@Nullable VolumeShaper.Configuration volumeShaperConfig) { - mVolumeShaperConfig = volumeShaperConfig; - } - - /** - * Set {@link Uri} to be used for ringtone playback. Attempts to open - * locally, otherwise will delegate playback to remote - * {@link IRingtonePlayer}. Add {@link VolumeShaper} if required. - * - * @hide - */ - public void setUri(Uri uri, @Nullable VolumeShaper.Configuration volumeShaperConfig) { - mVolumeShaperConfig = volumeShaperConfig; - mUri = uri; - if (mUri == null) { - destroyLocalPlayer(); - } - } - - /** {@hide} */ - @UnsupportedAppUsage - public Uri getUri() { - return mUri; - } - - /** - * Plays the ringtone. - */ - public void play() { - if (mLocalPlayer != null) { - // Play ringtones if stream volume is over 0 or if it is a haptic-only ringtone - // (typically because ringer mode is vibrate). - if (mAudioManager.getStreamVolume(AudioAttributes.toLegacyStreamType(mAudioAttributes)) - != 0) { - startLocalPlayer(); - } else if (!mAudioAttributes.areHapticChannelsMuted() && hasHapticChannels()) { - // is haptic only ringtone - startLocalPlayer(); - } - } else if (mAllowRemote && (mRemotePlayer != null) && (mUri != null)) { - final Uri canonicalUri = mUri.getCanonicalUri(); - final boolean looping; - final float volume; - synchronized (mPlaybackSettingsLock) { - looping = mIsLooping; - volume = mVolume; - } - try { - mRemotePlayer.playWithVolumeShaping(mRemoteToken, canonicalUri, mAudioAttributes, - volume, looping, mVolumeShaperConfig); - } catch (RemoteException e) { - if (!playFallbackRingtone()) { - Log.w(TAG, "Problem playing ringtone: " + e); - } - } - } else { - if (!playFallbackRingtone()) { - Log.w(TAG, "Neither local nor remote playback available"); - } - } - } - - /** - * Stops a playing ringtone. - */ - public void stop() { - if (mLocalPlayer != null) { - destroyLocalPlayer(); - } else if (mAllowRemote && (mRemotePlayer != null)) { - try { - mRemotePlayer.stop(mRemoteToken); - } catch (RemoteException e) { - Log.w(TAG, "Problem stopping ringtone: " + e); - } - } - } - - private void destroyLocalPlayer() { - if (mLocalPlayer != null) { - if (mHapticGenerator != null) { - mHapticGenerator.release(); - mHapticGenerator = null; - } - mLocalPlayer.setOnCompletionListener(null); - mLocalPlayer.reset(); - mLocalPlayer.release(); - mLocalPlayer = null; - mVolumeShaper = null; - synchronized (sActiveRingtones) { - sActiveRingtones.remove(this); - } - } - } - - private void startLocalPlayer() { - if (mLocalPlayer == null) { - return; - } - synchronized (sActiveRingtones) { - sActiveRingtones.add(this); - } - if (LOGD) { - Log.d(TAG, "Starting ringtone playback"); - } - mLocalPlayer.setOnCompletionListener(mCompletionListener); - mLocalPlayer.start(); - if (mVolumeShaper != null) { - mVolumeShaper.apply(VolumeShaper.Operation.PLAY); - } - } - - /** - * Whether this ringtone is currently playing. - * - * @return True if playing, false otherwise. - */ - public boolean isPlaying() { - if (mLocalPlayer != null) { - return mLocalPlayer.isPlaying(); - } else if (mAllowRemote && (mRemotePlayer != null)) { - try { - return mRemotePlayer.isPlaying(mRemoteToken); - } catch (RemoteException e) { - Log.w(TAG, "Problem checking ringtone: " + e); - return false; - } - } else { - Log.w(TAG, "Neither local nor remote playback available"); - return false; - } - } - - private boolean playFallbackRingtone() { - int streamType = AudioAttributes.toLegacyStreamType(mAudioAttributes); - if (mAudioManager.getStreamVolume(streamType) == 0) { - return false; - } - int ringtoneType = RingtoneManager.getDefaultType(mUri); - if (ringtoneType != -1 && - RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) == null) { - Log.w(TAG, "not playing fallback for " + mUri); - return false; - } - // Default ringtone, try fallback ringtone. - try { - AssetFileDescriptor afd = mContext.getResources().openRawResourceFd( - com.android.internal.R.raw.fallbackring); - if (afd == null) { - Log.e(TAG, "Could not load fallback ringtone"); - return false; - } - mLocalPlayer = new MediaPlayer(); - if (afd.getDeclaredLength() < 0) { - mLocalPlayer.setDataSource(afd.getFileDescriptor()); - } else { - mLocalPlayer.setDataSource(afd.getFileDescriptor(), - afd.getStartOffset(), - afd.getDeclaredLength()); - } - mLocalPlayer.setAudioAttributes(mAudioAttributes); - synchronized (mPlaybackSettingsLock) { - applyPlaybackProperties_sync(); - } - if (mVolumeShaperConfig != null) { - mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig); - } - mLocalPlayer.prepare(); - startLocalPlayer(); - afd.close(); - } catch (IOException ioe) { - destroyLocalPlayer(); - Log.e(TAG, "Failed to open fallback ringtone"); - return false; - } catch (NotFoundException nfe) { - Log.e(TAG, "Fallback ringtone does not exist"); - return false; - } - return true; - } - - public boolean getPreferBuiltinDevice() { - return mPreferBuiltinDevice; - } - - public VolumeShaper.Configuration getVolumeShaperConfig() { - return mVolumeShaperConfig; - } - - public boolean isLocalOnly() { - return mAllowRemote; - } - - public boolean isUsingRemotePlayer() { - // V2 testing api, but this is the v1 approximation. - return (mLocalPlayer == null) && mAllowRemote && (mRemotePlayer != null); - } - - class MyOnCompletionListener implements MediaPlayer.OnCompletionListener { - @Override - public void onCompletion(MediaPlayer mp) { - synchronized (sActiveRingtones) { - sActiveRingtones.remove(RingtoneV1.this); - } - mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle. - } - } -} diff --git a/media/java/android/media/RingtoneV2.java b/media/java/android/media/RingtoneV2.java deleted file mode 100644 index f1a81553bdfc..000000000000 --- a/media/java/android/media/RingtoneV2.java +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (C) 2023 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 android.media; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources.NotFoundException; -import android.media.Ringtone.Injectables; -import android.net.Uri; -import android.os.Binder; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.Trace; -import android.os.VibrationEffect; -import android.os.Vibrator; -import android.provider.MediaStore; -import android.provider.MediaStore.MediaColumns; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * New Ringtone implementation, supporting vibration as well as sound, and configuration via a - * builder. During flagged transition, the original implementation is in RingtoneV1.java. - * - * Only modified methods are moved here. - * - * @hide - */ -class RingtoneV2 implements Ringtone.ApiInterface { - private static final String TAG = "RingtoneV2"; - - /** - * The ringtone should only play sound. Any vibration is managed externally. - * @hide - */ - public static final int MEDIA_SOUND = 1; - /** - * The ringtone should only play vibration. Any sound is managed externally. - * Requires the {@link android.Manifest.permission#VIBRATE} permission. - * @hide - */ - public static final int MEDIA_VIBRATION = 1 << 1; - /** - * The ringtone should play sound and vibration. - * @hide - */ - public static final int MEDIA_SOUND_AND_VIBRATION = MEDIA_SOUND | MEDIA_VIBRATION; - - // This is not a public value, because apps shouldn't enable "all" media - that wouldn't be - // safe if new media types were added. - static final int MEDIA_ALL = MEDIA_SOUND | MEDIA_VIBRATION; - - /** - * Declares the types of media that this Ringtone is allowed to play. - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "MEDIA_", value = { - MEDIA_SOUND, - MEDIA_VIBRATION, - MEDIA_SOUND_AND_VIBRATION, - }) - public @interface RingtoneMedia {} - - private static final String[] MEDIA_COLUMNS = new String[] { - MediaStore.Audio.Media._ID, - MediaStore.Audio.Media.TITLE - }; - /** Selection that limits query results to just audio files */ - private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%' OR " - + MediaColumns.MIME_TYPE + " IN ('application/ogg', 'application/x-flac')"; - - private final Context mContext; - private final Vibrator mVibrator; - private final AudioManager mAudioManager; - private VolumeShaper.Configuration mVolumeShaperConfig; - - /** - * Flag indicating if we're allowed to fall back to remote playback using - * {@link #mRemoteRingtoneService}. Typically this is false when we're the remote - * player and there is nobody else to delegate to. - */ - private final boolean mAllowRemote; - private final IRingtonePlayer mRemoteRingtoneService; - private final Injectables mInjectables; - - private final int mEnabledMedia; - - private final Uri mUri; - private String mTitle; - - private AudioAttributes mAudioAttributes; - private boolean mUseExactAudioAttributes; - private boolean mPreferBuiltinDevice; - private RingtonePlayer mActivePlayer; - // playback properties, use synchronized with mPlaybackSettingsLock - private boolean mIsLooping; - private float mVolume; - private boolean mHapticGeneratorEnabled; - private final Object mPlaybackSettingsLock = new Object(); - private final VibrationEffect mVibrationEffect; - - /** Only for use by Ringtone constructor */ - RingtoneV2(@NonNull Context context, @NonNull Injectables injectables, - boolean allowRemote, @Ringtone.RingtoneMedia int enabledMedia, - @Nullable Uri uri, @NonNull AudioAttributes audioAttributes, - boolean useExactAudioAttributes, - @Nullable VolumeShaper.Configuration volumeShaperConfig, - boolean preferBuiltinDevice, float soundVolume, boolean looping, - boolean hapticGeneratorEnabled, @Nullable VibrationEffect vibrationEffect) { - // Context - mContext = context; - mInjectables = injectables; - mVibrator = mContext.getSystemService(Vibrator.class); - mAudioManager = mContext.getSystemService(AudioManager.class); - mRemoteRingtoneService = allowRemote ? mAudioManager.getRingtonePlayer() : null; - mAllowRemote = (mRemoteRingtoneService != null); // Only set if allowed, and present. - - // Properties potentially propagated to remote player. - mEnabledMedia = enabledMedia; - mUri = uri; - mAudioAttributes = audioAttributes; - mUseExactAudioAttributes = useExactAudioAttributes; - mVolumeShaperConfig = volumeShaperConfig; - mPreferBuiltinDevice = preferBuiltinDevice; // system-only, not supported for remote play. - mVolume = soundVolume; - mIsLooping = looping; - mHapticGeneratorEnabled = hapticGeneratorEnabled; - mVibrationEffect = vibrationEffect; - } - - /** @hide */ - @RingtoneMedia - public int getEnabledMedia() { - return mEnabledMedia; - } - - /** - * Sets the stream type where this ringtone will be played. - * - * @param streamType The stream, see {@link AudioManager}. - * @deprecated use {@link #setAudioAttributes(AudioAttributes)} - */ - @Deprecated - public void setStreamType(int streamType) { - setAudioAttributes( - getAudioAttributesForLegacyStreamType(streamType, "setStreamType()")); - } - - private AudioAttributes getAudioAttributesForLegacyStreamType(int streamType, String originOp) { - PlayerBase.deprecateStreamTypeForPlayback(streamType, "Ringtone", originOp); - return new AudioAttributes.Builder() - .setInternalLegacyStreamType(streamType) - .build(); - } - - /** - * Gets the stream type where this ringtone will be played. - * - * @return The stream type, see {@link AudioManager}. - * @deprecated use of stream types is deprecated, see - * {@link #setAudioAttributes(AudioAttributes)} - */ - @Deprecated - public int getStreamType() { - return AudioAttributes.toLegacyStreamType(mAudioAttributes); - } - - /** - * Sets the {@link AudioAttributes} for this ringtone. - * @param attributes the non-null attributes characterizing this ringtone. - */ - public void setAudioAttributes(AudioAttributes attributes) - throws IllegalArgumentException { - // TODO: deprecate this method - it will be done with a builder. - if (attributes == null) { - throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone"); - } - mAudioAttributes = attributes; - // Setting the audio attributes requires re-initializing the player. - if (mActivePlayer != null) { - // The audio attributes have to be set before the media player is prepared. - // Re-initialize it. - reinitializeActivePlayer(); - } - } - - /** - * Returns the vibration effect that this ringtone was created with, if vibration is enabled. - * Otherwise, returns null. - * @hide - */ - @Nullable - public VibrationEffect getVibrationEffect() { - return mVibrationEffect; - } - - /** @hide */ - @VisibleForTesting - public boolean getPreferBuiltinDevice() { - return mPreferBuiltinDevice; - } - - /** @hide */ - @VisibleForTesting - public VolumeShaper.Configuration getVolumeShaperConfig() { - return mVolumeShaperConfig; - } - - /** - * Returns whether this player is local only, or can defer to the remote player. The - * result may differ from the builder if there is no remote player available at all. - * @hide - */ - @VisibleForTesting - public boolean isLocalOnly() { - return !mAllowRemote; - } - - /** @hide */ - @VisibleForTesting - public boolean isUsingRemotePlayer() { - return mActivePlayer instanceof RemoteRingtonePlayer; - } - - /** - * Finds the output device of type {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. This device is - * the one on which outgoing audio for SIM calls is played. - * - * @param audioManager the audio manage. - * @return the {@link AudioDeviceInfo} corresponding to the builtin device, or {@code null} if - * none can be found. - */ - private AudioDeviceInfo getBuiltinDevice(AudioManager audioManager) { - AudioDeviceInfo[] deviceList = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); - for (AudioDeviceInfo device : deviceList) { - if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { - return device; - } - } - return null; - } - - /** - * Creates a local media player for the ringtone using currently set attributes. - * @return true if media player creation succeeded or is deferred, - * false if it did not succeed and can't be tried remotely. - * @hide - */ - public boolean reinitializeActivePlayer() { - // Try creating a local media player, or fallback to creating a remote one. - Trace.beginSection("reinitializeActivePlayer"); - try { - if (mActivePlayer != null) { - // This would only happen if calling the deprecated setAudioAttributes after - // building the Ringtone. - stopAndReleaseActivePlayer(); - } - - boolean vibrationOnly = (mEnabledMedia & MEDIA_ALL) == MEDIA_VIBRATION; - // Vibration can come from the audio file if using haptic generator or if haptic - // channels are a possibility. - boolean maybeAudioVibration = mUri != null && mInjectables.isHapticPlaybackSupported() - && (mHapticGeneratorEnabled || !mAudioAttributes.areHapticChannelsMuted()); - - // VibrationEffect only, use the simplified player without checking for haptic channels. - if (vibrationOnly && !maybeAudioVibration && mVibrationEffect != null) { - mActivePlayer = new LocalRingtonePlayer.VibrationEffectPlayer( - mVibrationEffect, mAudioAttributes, mVibrator, mIsLooping); - return true; - } - - AudioDeviceInfo preferredDevice = - mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null; - if (mUri != null) { - mActivePlayer = LocalRingtonePlayer.create(mContext, mAudioManager, mVibrator, mUri, - mAudioAttributes, vibrationOnly, mVibrationEffect, mInjectables, - mVolumeShaperConfig, preferredDevice, mHapticGeneratorEnabled, mIsLooping, - mVolume); - } else { - // Using the remote player won't help play a null Uri. Revert straight to fallback. - // The vibration-only case was already covered above. - mActivePlayer = createFallbackRingtonePlayer(); - // Fall through to attempting remote fallback play if null. - } - - if (mActivePlayer == null && mAllowRemote) { - mActivePlayer = new RemoteRingtonePlayer(mRemoteRingtoneService, mUri, - mAudioAttributes, mUseExactAudioAttributes, mEnabledMedia, mVibrationEffect, - mVolumeShaperConfig, mHapticGeneratorEnabled, mIsLooping, mVolume); - } - - return mActivePlayer != null; - } finally { - if (mActivePlayer != null) { - Log.d(TAG, "Initialized ringtone player with " + mActivePlayer.getClass()); - } else { - Log.d(TAG, "Failed to initialize ringtone player"); - } - Trace.endSection(); - } - } - - @Nullable - private LocalRingtonePlayer createFallbackRingtonePlayer() { - int ringtoneType = RingtoneManager.getDefaultType(mUri); - if (ringtoneType != -1 - && RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) == null) { - Log.w(TAG, "not playing fallback for " + mUri); - return null; - } - // Default ringtone, try fallback ringtone. - try (AssetFileDescriptor afd = mContext.getResources().openRawResourceFd( - com.android.internal.R.raw.fallbackring)) { - if (afd == null) { - Log.e(TAG, "Could not load fallback ringtone"); - return null; - } - - AudioDeviceInfo preferredDevice = - mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null; - return LocalRingtonePlayer.createForFallback(mAudioManager, mVibrator, afd, - mAudioAttributes, mVibrationEffect, mInjectables, mVolumeShaperConfig, - preferredDevice, mIsLooping, mVolume); - } catch (NotFoundException nfe) { - Log.e(TAG, "Fallback ringtone does not exist"); - return null; - } catch (IOException e) { - // As with the above messages, not including much information about the - // failure so as not to expose details of the fallback ringtone resource. - Log.e(TAG, "Exception reading fallback ringtone"); - return null; - } - } - - /** - * Same as AudioManager.hasHapticChannels except it assumes an already created ringtone. - * @hide - */ - public boolean hasHapticChannels() { - return (mActivePlayer == null) ? false : mActivePlayer.hasHapticChannels(); - } - - /** - * Returns the {@link AudioAttributes} used by this object. - * @return the {@link AudioAttributes} that were set with - * {@link #setAudioAttributes(AudioAttributes)} or the default attributes if none were set. - */ - public AudioAttributes getAudioAttributes() { - return mAudioAttributes; - } - - /** - * Sets the player to be looping or non-looping. - * @param looping whether to loop or not. - */ - public void setLooping(boolean looping) { - synchronized (mPlaybackSettingsLock) { - mIsLooping = looping; - if (mActivePlayer != null) { - mActivePlayer.setLooping(looping); - } - } - } - - /** - * Returns whether the looping mode was enabled on this player. - * @return true if this player loops when playing. - */ - public boolean isLooping() { - synchronized (mPlaybackSettingsLock) { - return mIsLooping; - } - } - - /** - * Sets the volume on this player. - * @param volume a raw scalar in range 0.0 to 1.0, where 0.0 mutes this player, and 1.0 - * corresponds to no attenuation being applied. - */ - public void setVolume(float volume) { - // Ignore if sound not enabled. - if ((mEnabledMedia & MEDIA_SOUND) == 0) { - return; - } - if (volume < 0.0f) { - volume = 0.0f; - } else if (volume > 1.0f) { - volume = 1.0f; - } - - synchronized (mPlaybackSettingsLock) { - mVolume = volume; - if (mActivePlayer != null) { - mActivePlayer.setVolume(volume); - } - } - } - - /** - * Returns the volume scalar set on this player. - * @return a value between 0.0f and 1.0f. - */ - public float getVolume() { - synchronized (mPlaybackSettingsLock) { - return mVolume; - } - } - - /** - * Enable or disable the {@link android.media.audiofx.HapticGenerator} effect. The effect can - * only be enabled on devices that support the effect. - * - * @return true if the HapticGenerator effect is successfully enabled. Otherwise, return false. - * @see android.media.audiofx.HapticGenerator#isAvailable() - */ - public boolean setHapticGeneratorEnabled(boolean enabled) { - if (!mInjectables.isHapticGeneratorAvailable()) { - return false; - } - synchronized (mPlaybackSettingsLock) { - mHapticGeneratorEnabled = enabled; - if (mActivePlayer != null) { - mActivePlayer.setHapticGeneratorEnabled(enabled); - } - } - return true; - } - - /** - * Return whether the {@link android.media.audiofx.HapticGenerator} effect is enabled or not. - * @return true if the HapticGenerator is enabled. - */ - public boolean isHapticGeneratorEnabled() { - synchronized (mPlaybackSettingsLock) { - return mHapticGeneratorEnabled; - } - } - - /** - * Returns a human-presentable title for ringtone. Looks in media - * content provider. If not in either, uses the filename - * - * @param context A context used for querying. - */ - public String getTitle(Context context) { - if (mTitle != null) return mTitle; - return mTitle = Ringtone.getTitle(context, mUri, true /*followSettingsUri*/, mAllowRemote); - } - - - /** {@hide} */ - @UnsupportedAppUsage - public Uri getUri() { - return mUri; - } - - /** - * Plays the ringtone. - */ - public void play() { - if (mActivePlayer != null) { - Log.d(TAG, "Starting ringtone playback"); - if (mActivePlayer.play()) { - return; - } else { - // Discard active player: play() is only meant to be called once. - stopAndReleaseActivePlayer(); - } - } - if (!playFallbackRingtone()) { - Log.w(TAG, "Neither local nor remote playback available"); - } - } - - /** - * Stops a playing ringtone. - */ - public void stop() { - stopAndReleaseActivePlayer(); - } - - private void stopAndReleaseActivePlayer() { - if (mActivePlayer != null) { - mActivePlayer.stopAndRelease(); - mActivePlayer = null; - } - } - - /** - * Whether this ringtone is currently playing. - * - * @return True if playing, false otherwise. - */ - public boolean isPlaying() { - if (mActivePlayer != null) { - return mActivePlayer.isPlaying(); - } else { - Log.w(TAG, "No active ringtone player"); - return false; - } - } - - /** - * Fallback during the play stage rather than initialization, typically due to an issue - * communicating with the remote player. - */ - private boolean playFallbackRingtone() { - if (mActivePlayer != null) { - Log.wtf(TAG, "Playing fallback ringtone with another active player"); - stopAndReleaseActivePlayer(); - } - int streamType = AudioAttributes.toLegacyStreamType(mAudioAttributes); - if (mAudioManager.getStreamVolume(streamType) == 0) { - // TODO: Return true? If volume is off, this is a successful play. - return false; - } - mActivePlayer = createFallbackRingtonePlayer(); - if (mActivePlayer == null) { - return false; // the create method logs if it returns null. - } else if (mActivePlayer.play()) { - return true; - } else { - stopAndReleaseActivePlayer(); - return false; - } - } - - void setTitle(String title) { - mTitle = title; - } - - /** - * Play a specific ringtone. This interface is implemented by either local (this process) or - * proxied-remote playback via AudioManager.getRingtonePlayer, so that the caller - * (Ringtone class) can just use a single player after the initial creation. - * @hide - */ - interface RingtonePlayer { - /** - * Start playing the ringtone, returning false if there was a problem that - * requires falling back to the fallback ringtone resource. - */ - boolean play(); - boolean isPlaying(); - void stopAndRelease(); - - // Mutating playback methods. - void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo); - void setLooping(boolean looping); - void setHapticGeneratorEnabled(boolean enabled); - void setVolume(float volume); - - boolean hasHapticChannels(); - } - - /** - * Remote RingtonePlayer. All operations are delegated via the IRingtonePlayer interface, which - * should ultimately be backed by a RingtoneLocalPlayer within the system services. - */ - static class RemoteRingtonePlayer implements RingtonePlayer { - private final IBinder mRemoteToken = new Binder(); - private final IRingtonePlayer mRemoteRingtoneService; - private final Uri mCanonicalUri; - private final int mEnabledMedia; - private final VibrationEffect mVibrationEffect; - private final VolumeShaper.Configuration mVolumeShaperConfig; - private final AudioAttributes mAudioAttributes; - private final boolean mUseExactAudioAttributes; - private boolean mIsLooping; - private float mVolume; - private boolean mHapticGeneratorEnabled; - - RemoteRingtonePlayer(@NonNull IRingtonePlayer remoteRingtoneService, - @NonNull Uri uri, @NonNull AudioAttributes audioAttributes, - boolean useExactAudioAttributes, - @RingtoneMedia int enabledMedia, @Nullable VibrationEffect vibrationEffect, - @Nullable VolumeShaper.Configuration volumeShaperConfig, - boolean hapticGeneratorEnabled, boolean initialIsLooping, float initialVolume) { - mRemoteRingtoneService = remoteRingtoneService; - mCanonicalUri = (uri == null) ? null : uri.getCanonicalUri(); - mAudioAttributes = audioAttributes; - mUseExactAudioAttributes = useExactAudioAttributes; - mEnabledMedia = enabledMedia; - mVibrationEffect = vibrationEffect; - mVolumeShaperConfig = volumeShaperConfig; - mHapticGeneratorEnabled = hapticGeneratorEnabled; - mIsLooping = initialIsLooping; - mVolume = initialVolume; - } - - @Override - public boolean play() { - try { - mRemoteRingtoneService.playRemoteRingtone(mRemoteToken, mCanonicalUri, - mAudioAttributes, mUseExactAudioAttributes, mEnabledMedia, mVibrationEffect, - mVolume, mIsLooping, mHapticGeneratorEnabled, mVolumeShaperConfig); - return true; - } catch (RemoteException e) { - Log.w(TAG, "Problem playing ringtone: " + e); - return false; - } - } - - @Override - public boolean isPlaying() { - try { - return mRemoteRingtoneService.isPlaying(mRemoteToken); - } catch (RemoteException e) { - Log.w(TAG, "Problem checking ringtone isPlaying: " + e); - return false; - } - } - - @Override - public void stopAndRelease() { - try { - mRemoteRingtoneService.stop(mRemoteToken); - } catch (RemoteException e) { - Log.w(TAG, "Problem stopping ringtone: " + e); - } - } - - @Override - public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) { - // un-implemented for remote (but not used outside system). - } - - @Override - public void setLooping(boolean looping) { - mIsLooping = looping; - try { - mRemoteRingtoneService.setLooping(mRemoteToken, looping); - } catch (RemoteException e) { - Log.w(TAG, "Problem setting looping: " + e); - } - } - - @Override - public void setHapticGeneratorEnabled(boolean enabled) { - mHapticGeneratorEnabled = enabled; - try { - mRemoteRingtoneService.setHapticGeneratorEnabled(mRemoteToken, enabled); - } catch (RemoteException e) { - Log.w(TAG, "Problem setting hapticGeneratorEnabled: " + e); - } - } - - @Override - public void setVolume(float volume) { - mVolume = volume; - try { - mRemoteRingtoneService.setVolume(mRemoteToken, volume); - } catch (RemoteException e) { - Log.w(TAG, "Problem setting volume: " + e); - } - } - - @Override - public boolean hasHapticChannels() { - // FIXME: support remote player, or internalize haptic channels support and remove - // entirely. - return false; - } - } - -} diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java index 6817f534c00b..cb41eabfa87a 100644 --- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java +++ b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java @@ -19,7 +19,6 @@ package com.android.soundpicker; import android.content.Context; import android.media.AudioAttributes; import android.media.Ringtone; -import android.media.RingtoneManager; import android.net.Uri; import dagger.hilt.android.qualifiers.ApplicationContext; @@ -54,7 +53,10 @@ public class RingtoneFactory { .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setFlags(audioAttributesFlags) .build(); - return RingtoneManager.getRingtone(mApplicationContext, uri, - /* volumeShaperConfig= */ null, audioAttributes); + // TODO: We are currently only using MEDIA_SOUND for enabledMedia. This will change once we + // start playing sound and/or vibration. + return new Ringtone.Builder(mApplicationContext, Ringtone.MEDIA_SOUND, audioAttributes) + .setUri(uri) + .build(); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index 53d84f6bde65..40ab51d914bd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -57,7 +57,7 @@ import javax.inject.Inject; @SysUISingleton public class RingtonePlayer implements CoreStartable { private static final String TAG = "RingtonePlayer"; - private static final boolean LOGD = true; + private static final boolean LOGD = false; private final Context mContext; // TODO: support Uri switching under same IBinder @@ -111,53 +111,9 @@ public class RingtonePlayer implements CoreStartable { @Override public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping) throws RemoteException { - if (Ringtone.useRingtoneV2()) { - playRemoteRingtone(token, uri, aa, true, Ringtone.MEDIA_SOUND, - null, volume, looping, /* hapticGenerator= */ false, - null); - } else { - playWithVolumeShaping(token, uri, aa, volume, looping, null); - } - } - - @Override - public void playWithVolumeShaping( - IBinder token, Uri uri, AudioAttributes aa, float volume, - boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig) - throws RemoteException { - if (LOGD) { - Log.d(TAG, "playWithVolumeShaping(token=" + token + ", uri=" + uri + ", uid=" - + Binder.getCallingUid() + ")"); - } - Client client; - synchronized (mClients) { - client = mClients.get(token); - } - // Don't hold the lock while constructing the ringtone, since it can be slow. The caller - // shouldn't call play on the same ringtone from 2 threads, so this shouldn't race and - // waste the build. - if (client == null) { - final UserHandle user = Binder.getCallingUserHandle(); - Ringtone ringtone = Ringtone.createV1WithCustomAudioAttributes( - getContextForUser(user), aa, uri, volumeShaperConfig, - /* allowRemote= */ false); - synchronized (mClients) { - client = mClients.get(token); - if (client == null) { - client = new Client(token, ringtone); - token.linkToDeath(client, 0); - mClients.put(token, client); - ringtone = null; // "owned" by the client now. - } - } - // Clean up ringtone if it was abandoned (a client already existed). - if (ringtone != null) { - ringtone.stop(); - } - } - client.mRingtone.setLooping(looping); - client.mRingtone.setVolume(volume); - client.mRingtone.play(); + playRemoteRingtone(token, uri, aa, true, Ringtone.MEDIA_SOUND, + null, volume, looping, /* hapticGenerator= */ false, + null); } @Override @@ -169,7 +125,7 @@ public class RingtonePlayer implements CoreStartable { @Nullable VolumeShaper.Configuration volumeShaperConfig) throws RemoteException { if (LOGD) { - Log.d(TAG, "playRemoteRingtone(token=" + token + ", uri=" + uri + ", uid=" + Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" + Binder.getCallingUid() + ")"); } @@ -234,21 +190,6 @@ public class RingtonePlayer implements CoreStartable { return false; } } - @Override - public void setPlaybackProperties(IBinder token, float volume, boolean looping, - boolean hapticGeneratorEnabled) { - // RingtoneV1-exclusive path. - Client client; - synchronized (mClients) { - client = mClients.get(token); - } - if (client != null) { - client.mRingtone.setVolume(volume); - client.mRingtone.setLooping(looping); - client.mRingtone.setHapticGeneratorEnabled(hapticGeneratorEnabled); - } - // else no client for token when setting playback properties but will be set at play() - } @Override public void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled) { |