Loading media/java/android/media/LocalRingtonePlayer.java +14 −8 Original line number Diff line number Diff line Loading @@ -42,18 +42,22 @@ public class LocalRingtonePlayer private final MediaPlayer mMediaPlayer; private final AudioAttributes mAudioAttributes; private final Ringtone.Injectables mInjectables; 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) { @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator, @Nullable VolumeShaper volumeShaper) { Objects.requireNonNull(mediaPlayer); Objects.requireNonNull(audioAttributes); Objects.requireNonNull(injectables); Objects.requireNonNull(audioManager); mMediaPlayer = mediaPlayer; mAudioAttributes = audioAttributes; mInjectables = injectables; mAudioManager = audioManager; mVolumeShaper = volumeShaper; mHapticGenerator = hapticGenerator; Loading @@ -67,6 +71,7 @@ public class LocalRingtonePlayer static LocalRingtonePlayer create(@NonNull Context context, @NonNull AudioManager audioManager, @NonNull Uri soundUri, @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialHapticGeneratorEnabled, boolean initialLooping, float initialVolume) { Loading @@ -74,7 +79,7 @@ public class LocalRingtonePlayer Objects.requireNonNull(soundUri); Objects.requireNonNull(audioAttributes); Trace.beginSection("createLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); MediaPlayer mediaPlayer = injectables.newMediaPlayer(); HapticGenerator hapticGenerator = null; try { mediaPlayer.setDataSource(context, soundUri); Loading @@ -83,7 +88,7 @@ public class LocalRingtonePlayer mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); if (initialHapticGeneratorEnabled) { hapticGenerator = HapticGenerator.create(mediaPlayer.getAudioSessionId()); hapticGenerator = injectables.createHapticGenerator(mediaPlayer); hapticGenerator.setEnabled(true); } VolumeShaper volumeShaper = null; Loading @@ -91,7 +96,7 @@ public class LocalRingtonePlayer volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, return new LocalRingtonePlayer(mediaPlayer, audioAttributes, injectables, audioManager, hapticGenerator, volumeShaper); } catch (SecurityException | IOException e) { if (hapticGenerator != null) { Loading @@ -113,6 +118,7 @@ public class LocalRingtonePlayer static LocalRingtonePlayer createForFallback( @NonNull AudioManager audioManager, @NonNull AssetFileDescriptor afd, @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialLooping, float initialVolume) { Loading @@ -122,7 +128,7 @@ public class LocalRingtonePlayer Objects.requireNonNull(audioAttributes); Trace.beginSection("createFallbackLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); MediaPlayer mediaPlayer = injectables.newMediaPlayer(); try { if (afd.getDeclaredLength() < 0) { mediaPlayer.setDataSource(afd.getFileDescriptor()); Loading @@ -140,7 +146,7 @@ public class LocalRingtonePlayer volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, return new LocalRingtonePlayer(mediaPlayer, audioAttributes, injectables, audioManager, /* hapticGenerator= */ null, volumeShaper); } catch (SecurityException | IOException e) { Log.e(TAG, "Failed to open fallback ringtone"); Loading Loading @@ -202,7 +208,7 @@ public class LocalRingtonePlayer @Override public void setHapticGeneratorEnabled(boolean enabled) { if (enabled && mHapticGenerator == null) { mHapticGenerator = HapticGenerator.create(mMediaPlayer.getAudioSessionId()); mHapticGenerator = mInjectables.createHapticGenerator(mMediaPlayer); } if (mHapticGenerator != null) { mHapticGenerator.setEnabled(enabled); Loading media/java/android/media/Ringtone.java +330 −133 File changed.Preview size limit exceeded, changes collapsed. Show changes media/java/android/media/RingtoneManager.java +31 −94 Original line number Diff line number Diff line Loading @@ -353,6 +353,25 @@ public class RingtoneManager { } } /** @hide */ @NonNull public static AudioAttributes getDefaultAudioAttributes(int ringtoneType) { AudioAttributes.Builder builder = new AudioAttributes.Builder(); switch (ringtoneType) { case TYPE_ALARM: builder.setUsage(AudioAttributes.USAGE_ALARM); break; case TYPE_NOTIFICATION: builder.setUsage(AudioAttributes.USAGE_NOTIFICATION); break; default: // ringtone or all builder.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE); break; } builder.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION); return builder.build(); } /** * Whether retrieving another {@link Ringtone} will stop playing the * previously retrieved {@link Ringtone}. Loading Loading @@ -477,8 +496,10 @@ public class RingtoneManager { mPreviousRingtone.stop(); } mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true); mPreviousRingtone = new Ringtone.Builder( mContext, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(mType)) .setUri(getRingtoneUri(position)) .build(); return mPreviousRingtone; } Loading Loading @@ -673,40 +694,9 @@ public class RingtoneManager { * @return A {@link Ringtone} for the given URI, or null. */ public static Ringtone getRingtone(final Context context, Uri ringtoneUri) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1, true); } /** * Returns a {@link Ringtone} with {@link VolumeShaper} if required for a given sound URI. * <p> * If the given URI cannot be opened for any reason, this method will * attempt to fallback on another sound. If it cannot find any, it will * return null. * * @param context A context used to query. * @param ringtoneUri The {@link Uri} of a sound or ringtone. * @param volumeShaperConfig config for volume shaper of the ringtone if applied. * @return A {@link Ringtone} for the given URI, or null. * * @hide */ public static Ringtone getRingtone( final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, true); } /** * @hide */ public static Ringtone getRingtone(final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean createLocalMediaPlayer) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, createLocalMediaPlayer); return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1)) .setUri(ringtoneUri) .build(); } /** Loading @@ -715,64 +705,11 @@ public class RingtoneManager { public static Ringtone getRingtone(final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig, AudioAttributes audioAttributes) { // Don't set the stream type Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false); if (ringtone != null) { ringtone.setAudioAttributesField(audioAttributes); if (!ringtone.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } } return ringtone; } //FIXME bypass the notion of stream types within the class /** * Returns a {@link Ringtone} for a given sound URI on the given stream * type. Normally, if you change the stream type on the returned * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just * an optimized route to avoid that. * * @param streamType The stream type for the ringtone, or -1 if it should * 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#reinitializeActivePlayer()} in order to play the Ringtone. * @see #getRingtone(Context, Uri) */ @UnsupportedAppUsage private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType, boolean createLocalMediaPlayer) { return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */, createLocalMediaPlayer); } private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType, @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean createLocalMediaPlayer) { try { final Ringtone r = new Ringtone(context, true); if (streamType >= 0) { //FIXME deprecated call r.setStreamType(streamType); } r.setVolumeShaperConfig(volumeShaperConfig); r.setUri(ringtoneUri, volumeShaperConfig); if (createLocalMediaPlayer) { if (!r.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } } return r; } catch (Exception ex) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex); } return null; // TODO: move caller(s) away from this method: inline the builder call. return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, audioAttributes) .setUri(ringtoneUri) .setVolumeShaperConfig(volumeShaperConfig) .build(); } /** Loading media/tests/MediaFrameworkTest/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "android-ex-camera2", "testables", "testng", "truth-prebuilt", ], jni_libs: [ "libdexmakerjvmtiagent", Loading media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/OWNERS 0 → 100644 +2 −0 Original line number Diff line number Diff line # Haptics team also works on Ringtone per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS Loading
media/java/android/media/LocalRingtonePlayer.java +14 −8 Original line number Diff line number Diff line Loading @@ -42,18 +42,22 @@ public class LocalRingtonePlayer private final MediaPlayer mMediaPlayer; private final AudioAttributes mAudioAttributes; private final Ringtone.Injectables mInjectables; 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) { @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator, @Nullable VolumeShaper volumeShaper) { Objects.requireNonNull(mediaPlayer); Objects.requireNonNull(audioAttributes); Objects.requireNonNull(injectables); Objects.requireNonNull(audioManager); mMediaPlayer = mediaPlayer; mAudioAttributes = audioAttributes; mInjectables = injectables; mAudioManager = audioManager; mVolumeShaper = volumeShaper; mHapticGenerator = hapticGenerator; Loading @@ -67,6 +71,7 @@ public class LocalRingtonePlayer static LocalRingtonePlayer create(@NonNull Context context, @NonNull AudioManager audioManager, @NonNull Uri soundUri, @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialHapticGeneratorEnabled, boolean initialLooping, float initialVolume) { Loading @@ -74,7 +79,7 @@ public class LocalRingtonePlayer Objects.requireNonNull(soundUri); Objects.requireNonNull(audioAttributes); Trace.beginSection("createLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); MediaPlayer mediaPlayer = injectables.newMediaPlayer(); HapticGenerator hapticGenerator = null; try { mediaPlayer.setDataSource(context, soundUri); Loading @@ -83,7 +88,7 @@ public class LocalRingtonePlayer mediaPlayer.setLooping(initialLooping); mediaPlayer.setVolume(initialVolume); if (initialHapticGeneratorEnabled) { hapticGenerator = HapticGenerator.create(mediaPlayer.getAudioSessionId()); hapticGenerator = injectables.createHapticGenerator(mediaPlayer); hapticGenerator.setEnabled(true); } VolumeShaper volumeShaper = null; Loading @@ -91,7 +96,7 @@ public class LocalRingtonePlayer volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, return new LocalRingtonePlayer(mediaPlayer, audioAttributes, injectables, audioManager, hapticGenerator, volumeShaper); } catch (SecurityException | IOException e) { if (hapticGenerator != null) { Loading @@ -113,6 +118,7 @@ public class LocalRingtonePlayer static LocalRingtonePlayer createForFallback( @NonNull AudioManager audioManager, @NonNull AssetFileDescriptor afd, @NonNull AudioAttributes audioAttributes, @NonNull Ringtone.Injectables injectables, @Nullable VolumeShaper.Configuration volumeShaperConfig, @Nullable AudioDeviceInfo preferredDevice, boolean initialLooping, float initialVolume) { Loading @@ -122,7 +128,7 @@ public class LocalRingtonePlayer Objects.requireNonNull(audioAttributes); Trace.beginSection("createFallbackLocalMediaPlayer"); MediaPlayer mediaPlayer = new MediaPlayer(); MediaPlayer mediaPlayer = injectables.newMediaPlayer(); try { if (afd.getDeclaredLength() < 0) { mediaPlayer.setDataSource(afd.getFileDescriptor()); Loading @@ -140,7 +146,7 @@ public class LocalRingtonePlayer volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig); } mediaPlayer.prepare(); return new LocalRingtonePlayer(mediaPlayer, audioAttributes, audioManager, return new LocalRingtonePlayer(mediaPlayer, audioAttributes, injectables, audioManager, /* hapticGenerator= */ null, volumeShaper); } catch (SecurityException | IOException e) { Log.e(TAG, "Failed to open fallback ringtone"); Loading Loading @@ -202,7 +208,7 @@ public class LocalRingtonePlayer @Override public void setHapticGeneratorEnabled(boolean enabled) { if (enabled && mHapticGenerator == null) { mHapticGenerator = HapticGenerator.create(mMediaPlayer.getAudioSessionId()); mHapticGenerator = mInjectables.createHapticGenerator(mMediaPlayer); } if (mHapticGenerator != null) { mHapticGenerator.setEnabled(enabled); Loading
media/java/android/media/Ringtone.java +330 −133 File changed.Preview size limit exceeded, changes collapsed. Show changes
media/java/android/media/RingtoneManager.java +31 −94 Original line number Diff line number Diff line Loading @@ -353,6 +353,25 @@ public class RingtoneManager { } } /** @hide */ @NonNull public static AudioAttributes getDefaultAudioAttributes(int ringtoneType) { AudioAttributes.Builder builder = new AudioAttributes.Builder(); switch (ringtoneType) { case TYPE_ALARM: builder.setUsage(AudioAttributes.USAGE_ALARM); break; case TYPE_NOTIFICATION: builder.setUsage(AudioAttributes.USAGE_NOTIFICATION); break; default: // ringtone or all builder.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE); break; } builder.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION); return builder.build(); } /** * Whether retrieving another {@link Ringtone} will stop playing the * previously retrieved {@link Ringtone}. Loading Loading @@ -477,8 +496,10 @@ public class RingtoneManager { mPreviousRingtone.stop(); } mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true); mPreviousRingtone = new Ringtone.Builder( mContext, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(mType)) .setUri(getRingtoneUri(position)) .build(); return mPreviousRingtone; } Loading Loading @@ -673,40 +694,9 @@ public class RingtoneManager { * @return A {@link Ringtone} for the given URI, or null. */ public static Ringtone getRingtone(final Context context, Uri ringtoneUri) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1, true); } /** * Returns a {@link Ringtone} with {@link VolumeShaper} if required for a given sound URI. * <p> * If the given URI cannot be opened for any reason, this method will * attempt to fallback on another sound. If it cannot find any, it will * return null. * * @param context A context used to query. * @param ringtoneUri The {@link Uri} of a sound or ringtone. * @param volumeShaperConfig config for volume shaper of the ringtone if applied. * @return A {@link Ringtone} for the given URI, or null. * * @hide */ public static Ringtone getRingtone( final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, true); } /** * @hide */ public static Ringtone getRingtone(final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean createLocalMediaPlayer) { // Don't set the stream type return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, createLocalMediaPlayer); return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1)) .setUri(ringtoneUri) .build(); } /** Loading @@ -715,64 +705,11 @@ public class RingtoneManager { public static Ringtone getRingtone(final Context context, Uri ringtoneUri, @Nullable VolumeShaper.Configuration volumeShaperConfig, AudioAttributes audioAttributes) { // Don't set the stream type Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false); if (ringtone != null) { ringtone.setAudioAttributesField(audioAttributes); if (!ringtone.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } } return ringtone; } //FIXME bypass the notion of stream types within the class /** * Returns a {@link Ringtone} for a given sound URI on the given stream * type. Normally, if you change the stream type on the returned * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just * an optimized route to avoid that. * * @param streamType The stream type for the ringtone, or -1 if it should * 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#reinitializeActivePlayer()} in order to play the Ringtone. * @see #getRingtone(Context, Uri) */ @UnsupportedAppUsage private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType, boolean createLocalMediaPlayer) { return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */, createLocalMediaPlayer); } private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType, @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean createLocalMediaPlayer) { try { final Ringtone r = new Ringtone(context, true); if (streamType >= 0) { //FIXME deprecated call r.setStreamType(streamType); } r.setVolumeShaperConfig(volumeShaperConfig); r.setUri(ringtoneUri, volumeShaperConfig); if (createLocalMediaPlayer) { if (!r.reinitializeActivePlayer()) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri); return null; } } return r; } catch (Exception ex) { Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex); } return null; // TODO: move caller(s) away from this method: inline the builder call. return new Ringtone.Builder(context, Ringtone.MEDIA_SOUND, audioAttributes) .setUri(ringtoneUri) .setVolumeShaperConfig(volumeShaperConfig) .build(); } /** Loading
media/tests/MediaFrameworkTest/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ android_test { "androidx.test.ext.junit", "androidx.test.rules", "android-ex-camera2", "testables", "testng", "truth-prebuilt", ], jni_libs: [ "libdexmakerjvmtiagent", Loading
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/OWNERS 0 → 100644 +2 −0 Original line number Diff line number Diff line # Haptics team also works on Ringtone per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS