Loading media/java/android/media/IRingtonePlayer.aidl +5 −3 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ interface IRingtonePlayer { @UnsupportedAppUsage oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig); float volume, boolean looping, boolean hapticGeneratorEnabled, in @nullable VolumeShaper.Configuration volumeShaperConfig); oneway void stop(IBinder token); boolean isPlaying(IBinder token); oneway void setPlaybackProperties(IBinder token, float volume, boolean looping, boolean hapticGeneratorEnabled); oneway void setLooping(IBinder token, boolean looping); oneway void setVolume(IBinder token, float volume); oneway void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled); /** Used for Notification sound playback. */ oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa); Loading media/java/android/media/LocalRingtonePlayer.java 0 → 100644 +244 −0 Original line number Diff line number Diff line /* * 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.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.media.audiofx.HapticGenerator; import android.net.Uri; import android.os.Trace; import android.util.Log; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; /** * Plays a ringtone on the local process. * @hide */ public class LocalRingtonePlayer implements Ringtone.RingtonePlayer, MediaPlayer.OnCompletionListener { private static final String TAG = "LocalRingtonePlayer"; // keep references on active Ringtones until stopped or completion listener called. private static final ArrayList<LocalRingtonePlayer> sActiveRingtones = new ArrayList<>(); private final MediaPlayer mMediaPlayer; private final AudioAttributes mAudioAttributes; private final AudioManager mAudioManager; private final VolumeShaper mVolumeShaper; private HapticGenerator mHapticGenerator; private LocalRingtonePlayer(@NonNull MediaPlayer mediaPlayer, @NonNull AudioAttributes audioAttributes, @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator, @Nullable VolumeShaper volumeShaper) { Objects.requireNonNull(mediaPlayer); Objects.requireNonNull(audioAttributes); Objects.requireNonNull(audioManager); mMediaPlayer = mediaPlayer; mAudioAttributes = audioAttributes; mAudioManager = audioManager; mVolumeShaper = volumeShaper; mHapticGenerator = hapticGenerator; } /** * Creates a {@link LocalRingtonePlayer} for a Uri, returning null if the Uri can't be * loaded in the local player. */ @Nullable static LocalRingtonePlayer create(@NonNull Context context, @NonNull AudioManager audioManager, @NonNull Uri soundUri, @NonNull AudioAttributes audioAttributes, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialHapticGeneratorEnabled, boolean initialLooping, float initialVolume) { Objects.requireNonNull(context); Objects.requireNonNull(soundUri); Objects.requireNonNull(audioAttributes); Trace.beginSection("createLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); HapticGenerator hapticGenerator = null; try { mediaPlayer.setDataSource(context, soundUri); mediaPlayer.setAudioAttributes(audioAttributes); mediaPlayer.setPreferredDevice(preferredDevice); mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); if (initialHapticGeneratorEnabled) { hapticGenerator = HapticGenerator.create(mediaPlayer.getAudioSessionId()); hapticGenerator.setEnabled(true); } VolumeShaper volumeShaper = null; if (volumeShaperConfig != null) { volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, hapticGenerator, volumeShaper); } catch (SecurityException | IOException e) { if (hapticGenerator != null) { hapticGenerator.release(); } // volume shaper closes with media player mediaPlayer.release(); return null; } finally { Trace.endSection(); } } /** * Creates a {@link LocalRingtonePlayer} for an externally referenced file descriptor. This is * intended for loading a fallback from an internal resource, rather than via a Uri. */ @Nullable static LocalRingtonePlayer createForFallback( @NonNull AudioManager audioManager, @NonNull AssetFileDescriptor afd, @NonNull AudioAttributes audioAttributes, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialLooping, float initialVolume) { // Haptic generator not supported for fallback. Objects.requireNonNull(audioManager); Objects.requireNonNull(afd); Objects.requireNonNull(audioAttributes); Trace.beginSection("createFallbackLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); try { if (afd.getDeclaredLength() < 0) { mediaPlayer.setDataSource(afd.getFileDescriptor()); } else { mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength()); } mediaPlayer.setAudioAttributes(audioAttributes); mediaPlayer.setPreferredDevice(preferredDevice); mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); VolumeShaper volumeShaper = null; if (volumeShaperConfig != null) { volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, /* hapticGenerator= */ null, volumeShaper); } catch (SecurityException | IOException e) { Log.e(TAG, "Failed to open fallback ringtone"); mediaPlayer.release(); return null; } finally { Trace.endSection(); } } @Override public boolean play() { // 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 && (mAudioAttributes.areHapticChannelsMuted() || !hasHapticChannels())) { return true; // Successfully played while muted. } synchronized (sActiveRingtones) { sActiveRingtones.add(this); } mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.start(); if (mVolumeShaper != null) { mVolumeShaper.apply(VolumeShaper.Operation.PLAY); } return true; } @Override public boolean isPlaying() { return mMediaPlayer.isPlaying(); } @Override public void stopAndRelease() { synchronized (sActiveRingtones) { sActiveRingtones.remove(this); } if (mHapticGenerator != null) { mHapticGenerator.release(); } mMediaPlayer.setOnCompletionListener(null); mMediaPlayer.reset(); mMediaPlayer.release(); } @Override public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) { mMediaPlayer.setPreferredDevice(audioDeviceInfo); } @Override public void setLooping(boolean looping) { mMediaPlayer.setLooping(looping); } @Override public void setHapticGeneratorEnabled(boolean enabled) { if (enabled && mHapticGenerator == null) { mHapticGenerator = HapticGenerator.create(mMediaPlayer.getAudioSessionId()); } if (mHapticGenerator != null) { mHapticGenerator.setEnabled(enabled); } } @Override public void setVolume(float volume) { mMediaPlayer.setVolume(volume); } /** * Same as AudioManager.hasHapticChannels except it assumes an already created ringtone. * @hide */ @Override public boolean hasHapticChannels() { // FIXME: support remote player, or internalize haptic channels support and remove entirely. try { Trace.beginSection("LocalRingtonePlayer.hasHapticChannels"); for (MediaPlayer.TrackInfo trackInfo : mMediaPlayer.getTrackInfo()) { if (trackInfo.hasHapticChannels()) { return true; } } } finally { Trace.endSection(); } return false; } @Override public void onCompletion(MediaPlayer mp) { synchronized (sActiveRingtones) { sActiveRingtones.remove(this); } mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle. } } media/java/android/media/Ringtone.java +230 −223 File changed.Preview size limit exceeded, changes collapsed. Show changes media/java/android/media/RingtoneManager.java +3 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package android.media; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -39,10 +38,7 @@ import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; Loading Loading @@ -724,7 +720,7 @@ public class RingtoneManager { volumeShaperConfig, false); if (ringtone != null) { ringtone.setAudioAttributesField(audioAttributes); if (!ringtone.createLocalMediaPlayer()) { if (!ringtone.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } Loading @@ -743,7 +739,7 @@ public class RingtoneManager { * not be set (and the default used instead). * @param createLocalMediaPlayer when true, the ringtone returned will be fully * created otherwise, it will require the caller to create the media player manually * {@link Ringtone#createLocalMediaPlayer()} in order to play the Ringtone. * {@link Ringtone#reinitializeActivePlayer()} in order to play the Ringtone. * @see #getRingtone(Context, Uri) */ @UnsupportedAppUsage Loading @@ -766,7 +762,7 @@ public class RingtoneManager { r.setVolumeShaperConfig(volumeShaperConfig); r.setUri(ringtoneUri, volumeShaperConfig); if (createLocalMediaPlayer) { if (!r.createLocalMediaPlayer()) { if (!r.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } Loading packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +30 −8 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public class RingtonePlayer implements CoreStartable { mRingtone = new Ringtone(getContextForUser(user), false); mRingtone.setAudioAttributesField(aa); mRingtone.setUri(uri, volumeShaperConfig); mRingtone.createLocalMediaPlayer(); mRingtone.reinitializeActivePlayer(); } @Override Loading @@ -116,11 +116,14 @@ public class RingtonePlayer implements CoreStartable { @Override public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping) throws RemoteException { playWithVolumeShaping(token, uri, aa, volume, looping, null); playWithVolumeShaping(token, uri, aa, volume, looping, /* hapticGenerator= */ false, null); } @Override public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig) boolean looping, boolean isHapticGeneratorEnabled, @Nullable VolumeShaper.Configuration volumeShaperConfig) throws RemoteException { if (LOGD) { Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" Loading @@ -138,6 +141,7 @@ public class RingtonePlayer implements CoreStartable { } client.mRingtone.setLooping(looping); client.mRingtone.setVolume(volume); client.mRingtone.setHapticGeneratorEnabled(isHapticGeneratorEnabled); client.mRingtone.play(); } Loading Loading @@ -169,18 +173,36 @@ public class RingtonePlayer implements CoreStartable { } @Override public void setPlaybackProperties(IBinder token, float volume, boolean looping, boolean hapticGeneratorEnabled) { public void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled) { 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 setLooping(IBinder token, boolean looping) { Client client; synchronized (mClients) { client = mClients.get(token); } if (client != null) { client.mRingtone.setLooping(looping); } } @Override public void setVolume(IBinder token, float volume) { Client client; synchronized (mClients) { client = mClients.get(token); } if (client != null) { client.mRingtone.setVolume(volume); } } @Override Loading Loading
media/java/android/media/IRingtonePlayer.aidl +5 −3 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ interface IRingtonePlayer { @UnsupportedAppUsage oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping); oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig); float volume, boolean looping, boolean hapticGeneratorEnabled, in @nullable VolumeShaper.Configuration volumeShaperConfig); oneway void stop(IBinder token); boolean isPlaying(IBinder token); oneway void setPlaybackProperties(IBinder token, float volume, boolean looping, boolean hapticGeneratorEnabled); oneway void setLooping(IBinder token, boolean looping); oneway void setVolume(IBinder token, float volume); oneway void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled); /** Used for Notification sound playback. */ oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa); Loading
media/java/android/media/LocalRingtonePlayer.java 0 → 100644 +244 −0 Original line number Diff line number Diff line /* * 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.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.media.audiofx.HapticGenerator; import android.net.Uri; import android.os.Trace; import android.util.Log; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; /** * Plays a ringtone on the local process. * @hide */ public class LocalRingtonePlayer implements Ringtone.RingtonePlayer, MediaPlayer.OnCompletionListener { private static final String TAG = "LocalRingtonePlayer"; // keep references on active Ringtones until stopped or completion listener called. private static final ArrayList<LocalRingtonePlayer> sActiveRingtones = new ArrayList<>(); private final MediaPlayer mMediaPlayer; private final AudioAttributes mAudioAttributes; private final AudioManager mAudioManager; private final VolumeShaper mVolumeShaper; private HapticGenerator mHapticGenerator; private LocalRingtonePlayer(@NonNull MediaPlayer mediaPlayer, @NonNull AudioAttributes audioAttributes, @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator, @Nullable VolumeShaper volumeShaper) { Objects.requireNonNull(mediaPlayer); Objects.requireNonNull(audioAttributes); Objects.requireNonNull(audioManager); mMediaPlayer = mediaPlayer; mAudioAttributes = audioAttributes; mAudioManager = audioManager; mVolumeShaper = volumeShaper; mHapticGenerator = hapticGenerator; } /** * Creates a {@link LocalRingtonePlayer} for a Uri, returning null if the Uri can't be * loaded in the local player. */ @Nullable static LocalRingtonePlayer create(@NonNull Context context, @NonNull AudioManager audioManager, @NonNull Uri soundUri, @NonNull AudioAttributes audioAttributes, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialHapticGeneratorEnabled, boolean initialLooping, float initialVolume) { Objects.requireNonNull(context); Objects.requireNonNull(soundUri); Objects.requireNonNull(audioAttributes); Trace.beginSection("createLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); HapticGenerator hapticGenerator = null; try { mediaPlayer.setDataSource(context, soundUri); mediaPlayer.setAudioAttributes(audioAttributes); mediaPlayer.setPreferredDevice(preferredDevice); mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); if (initialHapticGeneratorEnabled) { hapticGenerator = HapticGenerator.create(mediaPlayer.getAudioSessionId()); hapticGenerator.setEnabled(true); } VolumeShaper volumeShaper = null; if (volumeShaperConfig != null) { volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, hapticGenerator, volumeShaper); } catch (SecurityException | IOException e) { if (hapticGenerator != null) { hapticGenerator.release(); } // volume shaper closes with media player mediaPlayer.release(); return null; } finally { Trace.endSection(); } } /** * Creates a {@link LocalRingtonePlayer} for an externally referenced file descriptor. This is * intended for loading a fallback from an internal resource, rather than via a Uri. */ @Nullable static LocalRingtonePlayer createForFallback( @NonNull AudioManager audioManager, @NonNull AssetFileDescriptor afd, @NonNull AudioAttributes audioAttributes, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialLooping, float initialVolume) { // Haptic generator not supported for fallback. Objects.requireNonNull(audioManager); Objects.requireNonNull(afd); Objects.requireNonNull(audioAttributes); Trace.beginSection("createFallbackLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); try { if (afd.getDeclaredLength() < 0) { mediaPlayer.setDataSource(afd.getFileDescriptor()); } else { mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength()); } mediaPlayer.setAudioAttributes(audioAttributes); mediaPlayer.setPreferredDevice(preferredDevice); mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); VolumeShaper volumeShaper = null; if (volumeShaperConfig != null) { volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, /* hapticGenerator= */ null, volumeShaper); } catch (SecurityException | IOException e) { Log.e(TAG, "Failed to open fallback ringtone"); mediaPlayer.release(); return null; } finally { Trace.endSection(); } } @Override public boolean play() { // 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 && (mAudioAttributes.areHapticChannelsMuted() || !hasHapticChannels())) { return true; // Successfully played while muted. } synchronized (sActiveRingtones) { sActiveRingtones.add(this); } mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.start(); if (mVolumeShaper != null) { mVolumeShaper.apply(VolumeShaper.Operation.PLAY); } return true; } @Override public boolean isPlaying() { return mMediaPlayer.isPlaying(); } @Override public void stopAndRelease() { synchronized (sActiveRingtones) { sActiveRingtones.remove(this); } if (mHapticGenerator != null) { mHapticGenerator.release(); } mMediaPlayer.setOnCompletionListener(null); mMediaPlayer.reset(); mMediaPlayer.release(); } @Override public void setPreferredDevice(@Nullable AudioDeviceInfo audioDeviceInfo) { mMediaPlayer.setPreferredDevice(audioDeviceInfo); } @Override public void setLooping(boolean looping) { mMediaPlayer.setLooping(looping); } @Override public void setHapticGeneratorEnabled(boolean enabled) { if (enabled && mHapticGenerator == null) { mHapticGenerator = HapticGenerator.create(mMediaPlayer.getAudioSessionId()); } if (mHapticGenerator != null) { mHapticGenerator.setEnabled(enabled); } } @Override public void setVolume(float volume) { mMediaPlayer.setVolume(volume); } /** * Same as AudioManager.hasHapticChannels except it assumes an already created ringtone. * @hide */ @Override public boolean hasHapticChannels() { // FIXME: support remote player, or internalize haptic channels support and remove entirely. try { Trace.beginSection("LocalRingtonePlayer.hasHapticChannels"); for (MediaPlayer.TrackInfo trackInfo : mMediaPlayer.getTrackInfo()) { if (trackInfo.hasHapticChannels()) { return true; } } } finally { Trace.endSection(); } return false; } @Override public void onCompletion(MediaPlayer mp) { synchronized (sActiveRingtones) { sActiveRingtones.remove(this); } mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle. } }
media/java/android/media/Ringtone.java +230 −223 File changed.Preview size limit exceeded, changes collapsed. Show changes
media/java/android/media/RingtoneManager.java +3 −7 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package android.media; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -39,10 +38,7 @@ import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; Loading Loading @@ -724,7 +720,7 @@ public class RingtoneManager { volumeShaperConfig, false); if (ringtone != null) { ringtone.setAudioAttributesField(audioAttributes); if (!ringtone.createLocalMediaPlayer()) { if (!ringtone.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } Loading @@ -743,7 +739,7 @@ public class RingtoneManager { * not be set (and the default used instead). * @param createLocalMediaPlayer when true, the ringtone returned will be fully * created otherwise, it will require the caller to create the media player manually * {@link Ringtone#createLocalMediaPlayer()} in order to play the Ringtone. * {@link Ringtone#reinitializeActivePlayer()} in order to play the Ringtone. * @see #getRingtone(Context, Uri) */ @UnsupportedAppUsage Loading @@ -766,7 +762,7 @@ public class RingtoneManager { r.setVolumeShaperConfig(volumeShaperConfig); r.setUri(ringtoneUri, volumeShaperConfig); if (createLocalMediaPlayer) { if (!r.createLocalMediaPlayer()) { if (!r.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } Loading
packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +30 −8 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public class RingtonePlayer implements CoreStartable { mRingtone = new Ringtone(getContextForUser(user), false); mRingtone.setAudioAttributesField(aa); mRingtone.setUri(uri, volumeShaperConfig); mRingtone.createLocalMediaPlayer(); mRingtone.reinitializeActivePlayer(); } @Override Loading @@ -116,11 +116,14 @@ public class RingtonePlayer implements CoreStartable { @Override public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping) throws RemoteException { playWithVolumeShaping(token, uri, aa, volume, looping, null); playWithVolumeShaping(token, uri, aa, volume, looping, /* hapticGenerator= */ false, null); } @Override public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig) boolean looping, boolean isHapticGeneratorEnabled, @Nullable VolumeShaper.Configuration volumeShaperConfig) throws RemoteException { if (LOGD) { Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid=" Loading @@ -138,6 +141,7 @@ public class RingtonePlayer implements CoreStartable { } client.mRingtone.setLooping(looping); client.mRingtone.setVolume(volume); client.mRingtone.setHapticGeneratorEnabled(isHapticGeneratorEnabled); client.mRingtone.play(); } Loading Loading @@ -169,18 +173,36 @@ public class RingtonePlayer implements CoreStartable { } @Override public void setPlaybackProperties(IBinder token, float volume, boolean looping, boolean hapticGeneratorEnabled) { public void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled) { 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 setLooping(IBinder token, boolean looping) { Client client; synchronized (mClients) { client = mClients.get(token); } if (client != null) { client.mRingtone.setLooping(looping); } } @Override public void setVolume(IBinder token, float volume) { Client client; synchronized (mClients) { client = mClients.get(token); } if (client != null) { client.mRingtone.setVolume(volume); } } @Override Loading