Merge changes from topics "ringtone-flag-revert", "ringtone-local-revert", "ringtone-vibration-revert" into main

* changes:
  Remove SoundPicker2
  Revert "Add the haptics team to SoundPicker OWNERS."
  Revert "Add the haptics team to Ringtone OWNERS."
  Revert "Factor out ringtone local vs remote playback into separate implementations."
  Revert "Create a Builder for Ringtone, add unit tests."
  Revert "Remove bad finalizer from Ringtone."
  Revert "Add support for VibrationEffect and audio-coupled vibrations to Ringtone."
  Revert "Support vibration-only via Ringtone player."
  Revert "Add back the older Ringtone implementation to allow flag control."
  Revert "Create haptic vibration library"
  Revert "Add new extras and categories to the RingtoneManager class."
  Revert "Add a flag to enable RingtoneV2"
diff --git a/core/api/current.txt b/core/api/current.txt
index c896d5c..4eb7383 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24706,6 +24706,7 @@
   }
 
   public class Ringtone {
+    method protected void finalize();
     method public android.media.AudioAttributes getAudioAttributes();
     method @Deprecated public int getStreamType();
     method public String getTitle(android.content.Context);
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 08b32bf..c9c91fc 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -33,7 +33,6 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
-import android.util.Log;
 import android.util.MathUtils;
 
 import com.android.internal.util.Preconditions;
@@ -54,7 +53,6 @@
  * <p>These effects may be any number of things, from single shot vibrations to complex waveforms.
  */
 public abstract class VibrationEffect implements Parcelable {
-    private static final String TAG = "VibrationEffect";
     // Stevens' coefficient to scale the perceived vibration intensity.
     private static final float SCALE_GAMMA = 0.65f;
     // If a vibration is playing for longer than 1s, it's probably not haptic feedback
@@ -397,32 +395,26 @@
             return null;
         }
 
-        try {
-            final ContentResolver cr = context.getContentResolver();
-            Uri uncanonicalUri = cr.uncanonicalize(uri);
-            if (uncanonicalUri == null) {
-                // If we already had an uncanonical URI, it's possible we'll get null back here. In
-                // this case, just use the URI as passed in since it wasn't canonicalized in the
-                // first place.
-                uncanonicalUri = uri;
-            }
+        final ContentResolver cr = context.getContentResolver();
+        Uri uncanonicalUri = cr.uncanonicalize(uri);
+        if (uncanonicalUri == null) {
+            // If we already had an uncanonical URI, it's possible we'll get null back here. In
+            // this case, just use the URI as passed in since it wasn't canonicalized in the first
+            // place.
+            uncanonicalUri = uri;
+        }
 
-            for (int i = 0; i < uris.length && i < RINGTONES.length; i++) {
-                if (uris[i] == null) {
-                    continue;
-                }
-                Uri mappedUri = cr.uncanonicalize(Uri.parse(uris[i]));
-                if (mappedUri == null) {
-                    continue;
-                }
-                if (mappedUri.equals(uncanonicalUri)) {
-                    return get(RINGTONES[i]);
-                }
+        for (int i = 0; i < uris.length && i < RINGTONES.length; i++) {
+            if (uris[i] == null) {
+                continue;
             }
-        } catch (Exception e) {
-            // Don't give unexpected exceptions to callers if the Uri's ContentProvider is
-            // misbehaving - it's very unlikely to be mapped in that case anyway.
-            Log.e(TAG, "Exception getting default vibration for Uri " + uri, e);
+            Uri mappedUri = cr.uncanonicalize(Uri.parse(uris[i]));
+            if (mappedUri == null) {
+                continue;
+            }
+            if (mappedUri.equals(uncanonicalUri)) {
+                return get(RINGTONES[i]);
+            }
         }
         return null;
     }
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 437668c..ea9375e 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -16,13 +16,6 @@
 
 flag {
     namespace: "haptics"
-    name: "haptics_customization_ringtone_v2_enabled"
-    description: "Enables the usage of the new RingtoneV2 class"
-    bug: "241918098"
-}
-
-flag {
-    namespace: "haptics"
     name: "enable_vibration_serialization_apis"
     description: "Enables the APIs for vibration serialization/deserialization."
     bug: "245129509"
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 4fbe9ee..6ac9695 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -40,17 +40,6 @@
     },
     {
       "file_patterns": [
-        "[^/]*(Ringtone)[^/]*\\.java"
-      ],
-      "name": "MediaRingtoneTests",
-      "options": [
-        {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "androidx.test.filters.FlakyTest"},
-        {"exclude-annotation": "org.junit.Ignore"}
-      ]
-    },
-    {
-      "file_patterns": [
         "[^/]*(LoudnessCodec)[^/]*\\.java"
       ],
       "name": "LoudnessCodecApiTest",
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 1e57be2..c96a400 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -21,7 +21,6 @@
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
-import android.os.VibrationEffect;
 
 /**
  * @hide
@@ -30,23 +29,12 @@
     /** Used for Ringtone.java playback */
     @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);
     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 setLooping(IBinder token, boolean looping);
-    oneway void setVolume(IBinder token, float volume);
-    oneway void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled);
+        boolean hapticGeneratorEnabled);
 
     /** Used for Notification sound playback. */
     oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa, float volume);
diff --git a/media/java/android/media/LocalRingtonePlayer.java b/media/java/android/media/LocalRingtonePlayer.java
deleted file mode 100644
index fe7cc3e..0000000
--- a/media/java/android/media/LocalRingtonePlayer.java
+++ /dev/null
@@ -1,408 +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.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.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-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 RingtoneV2.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> sActiveMediaPlayers = new ArrayList<>();
-
-    private final MediaPlayer mMediaPlayer;
-    private final AudioAttributes mAudioAttributes;
-    private final RingtoneV2.RingtonePlayer mVibrationPlayer;
-    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 Ringtone.Injectables injectables,
-            @NonNull AudioManager audioManager, @Nullable HapticGenerator hapticGenerator,
-            @Nullable VolumeShaper volumeShaper,
-            @Nullable RingtoneV2.RingtonePlayer vibrationPlayer) {
-        Objects.requireNonNull(mediaPlayer);
-        Objects.requireNonNull(audioAttributes);
-        Objects.requireNonNull(injectables);
-        Objects.requireNonNull(audioManager);
-        mMediaPlayer = mediaPlayer;
-        mAudioAttributes = audioAttributes;
-        mInjectables = injectables;
-        mAudioManager = audioManager;
-        mVolumeShaper = volumeShaper;
-        mVibrationPlayer = vibrationPlayer;
-        mHapticGenerator = hapticGenerator;
-    }
-
-    /**
-     * Creates a {@link LocalRingtonePlayer} for a Uri, returning null if the Uri can't be
-     * loaded in the local player.
-     */
-    @Nullable
-    static RingtoneV2.RingtonePlayer create(@NonNull Context context,
-            @NonNull AudioManager audioManager, @NonNull Vibrator vibrator,
-            @NonNull Uri soundUri,
-            @NonNull AudioAttributes audioAttributes,
-            boolean isVibrationOnly,
-            @Nullable VibrationEffect vibrationEffect,
-            @NonNull Ringtone.Injectables injectables,
-            @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 = injectables.newMediaPlayer();
-        HapticGenerator hapticGenerator = null;
-        try {
-            mediaPlayer.setDataSource(context, soundUri);
-            mediaPlayer.setAudioAttributes(audioAttributes);
-            mediaPlayer.setPreferredDevice(preferredDevice);
-            mediaPlayer.setLooping(initialLooping);
-            mediaPlayer.setVolume(isVibrationOnly ? 0 : initialVolume);
-            if (initialHapticGeneratorEnabled) {
-                hapticGenerator = injectables.createHapticGenerator(mediaPlayer);
-                if (hapticGenerator != null) {
-                    // In practise, this should always be non-null because the initial value is
-                    // not true unless it's available.
-                    hapticGenerator.setEnabled(true);
-                    vibrationEffect = null;  // Don't play the VibrationEffect.
-                }
-            }
-            VolumeShaper volumeShaper = null;
-            if (volumeShaperConfig != null) {
-                volumeShaper = mediaPlayer.createVolumeShaper(volumeShaperConfig);
-            }
-            mediaPlayer.prepare();
-            if (vibrationEffect != null && !audioAttributes.areHapticChannelsMuted()) {
-                if (injectables.hasHapticChannels(mediaPlayer)) {
-                    // Don't play the Vibration effect if the URI has haptic channels.
-                    vibrationEffect = null;
-                }
-            }
-            VibrationEffectPlayer vibrationEffectPlayer = (vibrationEffect == null) ? null :
-                    new VibrationEffectPlayer(
-                            vibrationEffect, audioAttributes, vibrator, initialLooping);
-            if (isVibrationOnly && vibrationEffectPlayer != null) {
-                // Abandon the media player now that it's confirmed to not have haptic channels.
-                mediaPlayer.release();
-                return vibrationEffectPlayer;
-            }
-            return new LocalRingtonePlayer(mediaPlayer, audioAttributes, injectables, audioManager,
-                    hapticGenerator, volumeShaper, vibrationEffectPlayer);
-        } 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 Vibrator vibrator,
-            @NonNull AssetFileDescriptor afd,
-            @NonNull AudioAttributes audioAttributes,
-            @Nullable VibrationEffect vibrationEffect,
-            @NonNull Ringtone.Injectables injectables,
-            @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 = injectables.newMediaPlayer();
-        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();
-            if (vibrationEffect != null && !audioAttributes.areHapticChannelsMuted()) {
-                if (injectables.hasHapticChannels(mediaPlayer)) {
-                    // Don't play the Vibration effect if the URI has haptic channels.
-                    vibrationEffect = null;
-                }
-            }
-            VibrationEffectPlayer vibrationEffectPlayer = (vibrationEffect == null) ? null :
-                    new VibrationEffectPlayer(
-                            vibrationEffect, audioAttributes, vibrator, initialLooping);
-            return new LocalRingtonePlayer(mediaPlayer, audioAttributes,  injectables, audioManager,
-                    /* hapticGenerator= */ null, volumeShaper, vibrationEffectPlayer);
-        } catch (SecurityException | IOException e) {
-            Log.e(TAG, "Failed to open fallback ringtone");
-            // TODO: vibration-effect-only / no-sound LocalRingtonePlayer.
-            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())) {
-            maybeStartVibration();
-            return true;  // Successfully played while muted.
-        }
-        synchronized (sActiveMediaPlayers) {
-            // We keep-alive when a mediaplayer is active, since its finalizer would stop the
-            // ringtone. This isn't necessary for vibrations in the vibrator service
-            // (i.e. maybeStartVibration in the muted case, above).
-            sActiveMediaPlayers.add(this);
-        }
-
-        mMediaPlayer.setOnCompletionListener(this);
-        mMediaPlayer.start();
-        if (mVolumeShaper != null) {
-            mVolumeShaper.apply(VolumeShaper.Operation.PLAY);
-        }
-        maybeStartVibration();
-        return true;
-    }
-
-    private void maybeStartVibration() {
-        if (mVibrationPlayer != null) {
-            mVibrationPlayer.play();
-        }
-    }
-
-    @Override
-    public boolean isPlaying() {
-        return mMediaPlayer.isPlaying();
-    }
-
-    @Override
-    public void stopAndRelease() {
-        synchronized (sActiveMediaPlayers) {
-            sActiveMediaPlayers.remove(this);
-        }
-        try {
-            mMediaPlayer.stop();
-        } finally {
-            if (mVibrationPlayer != null) {
-                try {
-                    mVibrationPlayer.stopAndRelease();
-                } catch (Exception e) {
-                    Log.e(TAG, "Exception stopping ringtone vibration", e);
-                }
-            }
-            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) {
-        boolean wasLooping = mMediaPlayer.isLooping();
-        if (wasLooping == looping) {
-            return;
-        }
-        mMediaPlayer.setLooping(looping);
-        if (mVibrationPlayer != null) {
-            mVibrationPlayer.setLooping(looping);
-        }
-    }
-
-    @Override
-    public void setHapticGeneratorEnabled(boolean enabled) {
-        if (mVibrationPlayer != null) {
-            // Ignore haptic generator changes if a vibration player is present. The decision to
-            // use one or the other happens before this object is constructed.
-            return;
-        }
-        if (enabled && mHapticGenerator == null && !hasHapticChannels()) {
-            mHapticGenerator = mInjectables.createHapticGenerator(mMediaPlayer);
-        }
-        if (mHapticGenerator != null) {
-            mHapticGenerator.setEnabled(enabled);
-        }
-    }
-
-    @Override
-    public void setVolume(float volume) {
-        mMediaPlayer.setVolume(volume);
-        // no effect on vibration player
-    }
-
-    @Override
-    public boolean hasHapticChannels() {
-        return mInjectables.hasHapticChannels(mMediaPlayer);
-    }
-
-    @Override
-    public void onCompletion(MediaPlayer mp) {
-        synchronized (sActiveMediaPlayers) {
-            sActiveMediaPlayers.remove(this);
-        }
-        mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle.
-        // No effect on vibration: either it's looping and this callback only happens when stopped,
-        // or it's not looping, in which case the vibration should play to its own completion.
-    }
-
-    /** A RingtonePlayer that only plays a VibrationEffect. */
-    static class VibrationEffectPlayer implements RingtoneV2.RingtonePlayer {
-        private static final int VIBRATION_LOOP_DELAY_MS = 200;
-        private final VibrationEffect mVibrationEffect;
-        private final VibrationAttributes mVibrationAttributes;
-        private final Vibrator mVibrator;
-        private boolean mIsLooping;
-        private boolean mStartedVibration;
-
-        VibrationEffectPlayer(@NonNull VibrationEffect vibrationEffect,
-                @NonNull AudioAttributes audioAttributes,
-                @NonNull Vibrator vibrator, boolean initialLooping) {
-            mVibrationEffect = vibrationEffect;
-            mVibrationAttributes = new VibrationAttributes.Builder(audioAttributes).build();
-            mVibrator = vibrator;
-            mIsLooping = initialLooping;
-        }
-
-        @Override
-        public boolean play() {
-            if (!mStartedVibration) {
-                try {
-                    // Adjust the vibration effect to loop.
-                    VibrationEffect loopAdjustedEffect =
-                            mVibrationEffect.applyRepeatingIndefinitely(
-                                mIsLooping, VIBRATION_LOOP_DELAY_MS);
-                    mVibrator.vibrate(loopAdjustedEffect, mVibrationAttributes);
-                    mStartedVibration = true;
-                } catch (Exception e) {
-                    // Catch exceptions widely, because we don't want to "leak" looping sounds or
-                    // vibrations if something goes wrong.
-                    Log.e(TAG, "Problem starting " + (mIsLooping ? "looping " : "") + "vibration "
-                            + "for ringtone: " + mVibrationEffect, e);
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        @Override
-        public boolean isPlaying() {
-            return mStartedVibration;
-        }
-
-        @Override
-        public void stopAndRelease() {
-            if (mStartedVibration) {
-                try {
-                    mVibrator.cancel(mVibrationAttributes.getUsage());
-                    mStartedVibration = false;
-                } catch (Exception e) {
-                    // Catch exceptions widely, because we don't want to "leak" looping sounds or
-                    // vibrations if something goes wrong.
-                    Log.e(TAG, "Problem stopping vibration for ringtone", e);
-                }
-            }
-        }
-
-        @Override
-        public void setPreferredDevice(AudioDeviceInfo audioDeviceInfo) {
-            // no-op
-        }
-
-        @Override
-        public void setLooping(boolean looping) {
-            if (looping == mIsLooping) {
-                return;
-            }
-            mIsLooping = looping;
-            if (mStartedVibration) {
-                if (!mIsLooping) {
-                    // Was looping, stop looping
-                    stopAndRelease();
-                }
-                // Else was not looping, but can't interfere with a running vibration without
-                // restarting it, and don't know if it was finished. So do nothing: apps shouldn't
-                // toggle looping after calling play anyway.
-            }
-        }
-
-        @Override
-        public void setHapticGeneratorEnabled(boolean enabled) {
-            // n/a
-        }
-
-        @Override
-        public void setVolume(float volume) {
-            // n/a
-        }
-
-        @Override
-        public boolean hasHapticChannels() {
-            return false;
-        }
-    }
-}
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index 058c5be..49890c1 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -11,6 +11,3 @@
 
 per-file ExifInterface.java,ExifInterfaceUtils.java,IMediaHTTPConnection.aidl,IMediaHTTPService.aidl,JetPlayer.java,MediaDataSource.java,MediaExtractor.java,MediaHTTPConnection.java,MediaHTTPService.java,MediaPlayer.java=set noparent
 per-file ExifInterface.java,ExifInterfaceUtils.java,IMediaHTTPConnection.aidl,IMediaHTTPService.aidl,JetPlayer.java,MediaDataSource.java,MediaExtractor.java,MediaHTTPConnection.java,MediaHTTPService.java,MediaPlayer.java=file:platform/frameworks/av:/media/janitors/media_solutions_OWNERS
-
-# Haptics team also works on Ringtone
-per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 8800dc8..e78dc31 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -16,31 +16,27 @@
 
 package android.media;
 
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 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.Build;
 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.provider.Settings;
 import android.util.Log;
-
 import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.io.IOException;
+import java.util.ArrayList;
 
 /**
  * Ringtone provides a quick method for playing a ringtone, notification, or
@@ -53,39 +49,7 @@
  */
 public class Ringtone {
     private static final String TAG = "Ringtone";
-
-    /**
-     * 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 boolean LOGD = true;
 
     private static final String[] MEDIA_COLUMNS = new String[] {
         MediaStore.Audio.Media._ID,
@@ -95,70 +59,51 @@
     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;
+    // keep references on active Ringtones until stopped or completion listener called.
+    private static final ArrayList<Ringtone> sActiveRingtones = new ArrayList<Ringtone>();
+
+    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 Ringtone(Context context, boolean allowRemote) {
-        mApiImpl = new RingtoneV1(context, allowRemote);
-    }
-
-    /**
-     * Constructor for legacy V1 initialization paths using non-public APIs on RingtoneV1.
-     */
-    private Ringtone(RingtoneV1 ringtoneV1) {
-        mApiImpl = ringtoneV1;
-    }
-
-    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);
-    }
-
-    /** @hide */
-    @RingtoneMedia
-    public int getEnabledMedia() {
-        return mApiImpl.getEnabledMedia();
+        mContext = context;
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mAllowRemote = allowRemote;
+        mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null;
+        mRemoteToken = allowRemote ? new Binder() : null;
     }
 
     /**
@@ -169,7 +114,10 @@
      */
     @Deprecated
     public void setStreamType(int streamType) {
-        mApiImpl.setStreamType(streamType);
+        PlayerBase.deprecateStreamTypeForPlayback(streamType, "Ringtone", "setStreamType()");
+        setAudioAttributes(new AudioAttributes.Builder()
+                .setInternalLegacyStreamType(streamType)
+                .build());
     }
 
     /**
@@ -181,7 +129,7 @@
      */
     @Deprecated
     public int getStreamType() {
-        return mApiImpl.getStreamType();
+        return AudioAttributes.toLegacyStreamType(mAudioAttributes);
     }
 
     /**
@@ -190,45 +138,54 @@
      */
     public void setAudioAttributes(AudioAttributes attributes)
             throws IllegalArgumentException {
-        mApiImpl.setAudioAttributes(attributes);
+        setAudioAttributesField(attributes);
+        // The audio attributes have to be set before the media player is prepared.
+        // Re-initialize it.
+        setUri(mUri, mVolumeShaperConfig);
+        createLocalMediaPlayer();
     }
 
     /**
-     * Returns the vibration effect that this ringtone was created with, if vibration is enabled.
-     * Otherwise, returns null.
+     * Same as {@link #setAudioAttributes(AudioAttributes)} except this one does not create
+     * the media player.
      * @hide
      */
-    @Nullable
-    public VibrationEffect getVibrationEffect() {
-        return mApiImpl.getVibrationEffect();
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public boolean getPreferBuiltinDevice() {
-        return mApiImpl.getPreferBuiltinDevice();
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public VolumeShaper.Configuration getVolumeShaperConfig() {
-        return mApiImpl.getVolumeShaperConfig();
+    public void setAudioAttributesField(@Nullable AudioAttributes attributes) {
+        if (attributes == null) {
+            throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone");
+        }
+        mAudioAttributes = attributes;
     }
 
     /**
-     * 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
+     * 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.
      */
-    @VisibleForTesting
-    public boolean isLocalOnly() {
-        return mApiImpl.isLocalOnly();
+    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;
     }
 
-    /** @hide */
-    @VisibleForTesting
-    public boolean isUsingRemotePlayer() {
-        return mApiImpl.isUsingRemotePlayer();
+    /**
+     * 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));
     }
 
     /**
@@ -237,16 +194,76 @@
      * false if it did not succeed and can't be tried remotely.
      * @hide
      */
-    public boolean reinitializeActivePlayer() {
-        return mApiImpl.reinitializeActivePlayer();
+    public boolean createLocalMediaPlayer() {
+        Trace.beginSection("createLocalMediaPlayer");
+        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() {
-        return mApiImpl.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;
     }
 
     /**
@@ -255,7 +272,7 @@
      *     {@link #setAudioAttributes(AudioAttributes)} or the default attributes if none were set.
      */
     public AudioAttributes getAudioAttributes() {
-        return mApiImpl.getAudioAttributes();
+        return mAudioAttributes;
     }
 
     /**
@@ -263,7 +280,10 @@
      * @param looping whether to loop or not.
      */
     public void setLooping(boolean looping) {
-        mApiImpl.setLooping(looping);
+        synchronized (mPlaybackSettingsLock) {
+            mIsLooping = looping;
+            applyPlaybackProperties_sync();
+        }
     }
 
     /**
@@ -271,7 +291,9 @@
      * @return true if this player loops when playing.
      */
     public boolean isLooping() {
-        return mApiImpl.isLooping();
+        synchronized (mPlaybackSettingsLock) {
+            return mIsLooping;
+        }
     }
 
     /**
@@ -280,7 +302,12 @@
      *   corresponds to no attenuation being applied.
      */
     public void setVolume(float volume) {
-        mApiImpl.setVolume(volume);
+        synchronized (mPlaybackSettingsLock) {
+            if (volume < 0.0f) { volume = 0.0f; }
+            if (volume > 1.0f) { volume = 1.0f; }
+            mVolume = volume;
+            applyPlaybackProperties_sync();
+        }
     }
 
     /**
@@ -288,7 +315,9 @@
      * @return a value between 0.0f and 1.0f.
      */
     public float getVolume() {
-        return mApiImpl.getVolume();
+        synchronized (mPlaybackSettingsLock) {
+            return mVolume;
+        }
     }
 
     /**
@@ -299,7 +328,14 @@
      * @see android.media.audiofx.HapticGenerator#isAvailable()
      */
     public boolean setHapticGeneratorEnabled(boolean enabled) {
-        return mApiImpl.setHapticGeneratorEnabled(enabled);
+        if (!HapticGenerator.isAvailable()) {
+            return false;
+        }
+        synchronized (mPlaybackSettingsLock) {
+            mHapticGeneratorEnabled = enabled;
+            applyPlaybackProperties_sync();
+        }
+        return true;
     }
 
     /**
@@ -307,7 +343,35 @@
      * @return true if the HapticGenerator is enabled.
      */
     public boolean isHapticGeneratorEnabled() {
-        return mApiImpl.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");
+        }
     }
 
     /**
@@ -317,7 +381,8 @@
      * @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);
     }
 
     /**
@@ -391,24 +456,126 @@
         return title;
     }
 
+    /**
+     * 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 mApiImpl.getUri();
+        return mUri;
     }
 
     /**
      * Plays the ringtone.
      */
     public void play() {
-        mApiImpl.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() {
-        mApiImpl.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);
+        }
+        mLocalPlayer.setOnCompletionListener(mCompletionListener);
+        mLocalPlayer.start();
+        if (mVolumeShaper != null) {
+            mVolumeShaper.apply(VolumeShaper.Operation.PLAY);
+        }
     }
 
     /**
@@ -417,353 +584,87 @@
      * @return True if playing, false otherwise.
      */
     public boolean isPlaying() {
-        return mApiImpl.isPlaying();
-    }
-
-    /**
-     * Build a {@link Ringtone} to easily play sounds for ringtones, alarms and notifications.
-     *
-     * TODO: when un-hide, deprecate Ringtone: setAudioAttributes, setLooping,
-     *       setHapticGeneratorEnabled (no-effect if MEDIA_VIBRATION),
-     *       static RingtoneManager.getRingtone.
-     * @hide
-     */
-    public static final class Builder {
-        private final Context mContext;
-        private final int mEnabledMedia;
-        private Uri mUri;
-        private final AudioAttributes mAudioAttributes;
-        private boolean mUseExactAudioAttributes = false;
-        // Not a static default since it doesn't really need to be in memory forever.
-        private Injectables mInjectables = new Injectables();
-        private VolumeShaper.Configuration mVolumeShaperConfig;
-        private boolean mPreferBuiltinDevice = false;
-        private boolean mAllowRemote = true;
-        private boolean mHapticGeneratorEnabled = false;
-        private float mInitialSoundVolume = 1.0f;
-        private boolean mLooping = false;
-        private VibrationEffect mVibrationEffect;
-
-        /**
-         * Constructs a builder to play the given media types from the mediaUri. If the mediaUri
-         * is null (for example, an unset-setting), then fallback logic will dictate what plays.
-         *
-         * <p>When built, if the ringtone is already known to be a no-op, such as explicitly
-         * silent, then the {@link #build} may return null.
-         *
-         * @param context The context for playing the ringtone.
-         * @param enabledMedia Which media to play. Media not included is implicitly muted. Device
-         *                     settings such as volume and vibrate-only may also affect which
-         *                     media is played.
-         * @param audioAttributes The attributes to use for playback, which affects the volumes and
-         *                        settings that are applied.
-         */
-        public Builder(@NonNull Context context, @RingtoneMedia int enabledMedia,
-                @NonNull AudioAttributes audioAttributes) {
-            mContext = context;
-            mEnabledMedia = enabledMedia;
-            mAudioAttributes = audioAttributes;
-        }
-
-        /**
-         * Inject test intercepters for static methods.
-         * @hide
-         */
-        @NonNull
-        public Builder setInjectables(Injectables injectables) {
-            mInjectables = injectables;
-            return this;
-        }
-
-        /**
-         * The uri for the ringtone media to play. This is typically a user's preference for the
-         * sound. If null, then it is treated as though the user's preference is unset and
-         * fallback behavior, such as using the default ringtone setting, are used instead.
-         *
-         * When sound media is enabled, this is assumed to be a sound URI.
-         */
-        @NonNull
-        public Builder setUri(@Nullable Uri uri) {
-            mUri = uri;
-            return this;
-        }
-
-        /**
-         * Sets the VibrationEffect to use if vibration is enabled on this ringtone. The caller
-         * should use {@link android.os.Vibrator#areVibrationFeaturesSupported} to ensure
-         * that the effect is usable on this device, otherwise system defaults will be used.
-         *
-         * <p>Vibration will only happen if the Builder was created with media type
-         * {@link Ringtone#MEDIA_VIBRATION} or {@link Ringtone#MEDIA_SOUND_AND_VIBRATION}, and
-         * the application has the {@link android.Manifest.permission#VIBRATE} permission.
-         *
-         * <p>If the Ringtone is looping when it is played, then the VibrationEffect will be
-         * modified to loop. Similarly, if the ringtone is not looping, a repeating
-         * VibrationEffect will be modified to be non-repeating when the ringtone is played. Calls
-         * to {@link Ringtone#setLooping} after the ringtone has started playing will stop a looping
-         * vibration, but has no effect otherwise: specifically it will not restart vibration.
-         */
-        @NonNull
-        public Builder setVibrationEffect(@NonNull VibrationEffect effect) {
-            mVibrationEffect = effect;
-            return this;
-        }
-
-        /**
-         * Sets whether the resulting ringtone should loop until {@link Ringtone#stop()} is called,
-         * or just play once.
-         */
-        @NonNull
-        public Builder setLooping(boolean looping) {
-            mLooping = looping;
-            return this;
-        }
-
-        /**
-         * Sets the VolumeShaper.Configuration to apply to the ringtone.
-         * @hide
-         */
-        @NonNull
-        public Builder setVolumeShaperConfig(
-                @Nullable VolumeShaper.Configuration volumeShaperConfig) {
-            mVolumeShaperConfig = volumeShaperConfig;
-            return this;
-        }
-
-        /**
-         * Whether to enable or disable the haptic generator.
-         * @hide
-         */
-        @NonNull
-        public Builder setEnableHapticGenerator(boolean enabled) {
-            // Note that this property is mutable (but deprecated) on the Ringtone class itself.
-            mHapticGeneratorEnabled = enabled;
-            return this;
-        }
-
-        /**
-         * Sets the initial sound volume for the ringtone.
-         */
-        @NonNull
-        public Builder setInitialSoundVolume(float initialSoundVolume) {
-            mInitialSoundVolume = initialSoundVolume;
-            return this;
-        }
-
-        /**
-         * Sets the preferred device of the ringtone playback to the built-in device. This is
-         * only for use by the system server with known-good Uris.
-         * @hide
-         */
-        @NonNull
-        public Builder setPreferBuiltinDevice() {
-            mPreferBuiltinDevice = true;
-            mAllowRemote = false;  // Already in system.
-            return this;
-        }
-
-        /**
-         * Indicates that {@link AudioAttributes#areHapticChannelsMuted()} on the builder's
-         * AudioAttributes should not be overridden. This is used to enable legacy behavior of
-         * calling {@link Ringtone#setAudioAttributes} on an already-created ringtone, and can in
-         * turn cause vibration during a "sound-only" session or can suppress audio-coupled
-         * haptics that would usually take priority (therefore potentially falling back to
-         * the VibrationEffect or system defaults).
-         *
-         * <p>Without this setting, the haptic channels will be automatically muted or not by the
-         * Ringtone according to whether vibration is enabled or not.
-         *
-         * <p>This is for internal-use only. New applications should configure the vibration
-         * behavior explicitly with the (TODO: future RingtoneSetting.setVibrationSource).
-         * Handling haptic channels outside Ringtone leads to extra loads of the sound uri.
-         * @hide
-         */
-        @NonNull
-        public Builder setUseExactAudioAttributes(boolean useExactAttrs) {
-            mUseExactAudioAttributes = useExactAttrs;
-            return this;
-        }
-
-        /**
-         * Prevent fallback to the remote service. This is primarily intended for use within the
-         * remote IRingtonePlayer service itself, to avoid loops.
-         * @hide
-         */
-        @NonNull
-        public Builder setLocalOnly() {
-            mAllowRemote = false;
-            return this;
-        }
-
-        private boolean isVibrationEnabledAndAvailable() {
-            if ((mEnabledMedia & MEDIA_VIBRATION) == 0) {
-                return false;
-            }
-            Vibrator vibrator = mContext.getSystemService(Vibrator.class);
-            if (!vibrator.hasVibrator()) {
-                return false;
-            }
-            if (mContext.checkSelfPermission(Manifest.permission.VIBRATE)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Log.w(TAG, "Ringtone requests vibration enabled, but no VIBRATE permission");
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Returns the built Ringtone, or null if there was a problem loading the Uri and there
-         * are no fallback options available.
-         */
-        @Nullable
-        public Ringtone build() {
-            @Ringtone.RingtoneMedia int effectiveEnabledMedia = mEnabledMedia;
-            VibrationEffect effectiveVibrationEffect = mVibrationEffect;
-
-            // Normalize media to that supported on this SDK level.
-            if (effectiveEnabledMedia != (effectiveEnabledMedia & MEDIA_ALL)) {
-                Log.e(TAG, "Unsupported media type: " + effectiveEnabledMedia);
-                effectiveEnabledMedia = effectiveEnabledMedia & MEDIA_ALL;
-            }
-            final boolean effectiveHapticGenerator;
-            final boolean hapticChannelsSupported;
-            AudioAttributes effectiveAudioAttributes = mAudioAttributes;
-            final boolean hapticChannelsMuted = mAudioAttributes.areHapticChannelsMuted();
-            if (!isVibrationEnabledAndAvailable()) {
-                // Vibration isn't active: turn off everything that might cause extra work.
-                effectiveEnabledMedia &= ~MEDIA_VIBRATION;
-                effectiveHapticGenerator = false;
-                effectiveVibrationEffect = null;
-                if (!mUseExactAudioAttributes && !hapticChannelsMuted) {
-                    effectiveAudioAttributes = new AudioAttributes.Builder(effectiveAudioAttributes)
-                            .setHapticChannelsMuted(true)
-                            .build();
-                }
-            } else {
-                // Vibration is active.
-                effectiveHapticGenerator =
-                        mHapticGeneratorEnabled && mInjectables.isHapticGeneratorAvailable();
-                hapticChannelsSupported = mInjectables.isHapticPlaybackSupported();
-                // Haptic channels are preferred if they are available, and not explicitly muted.
-                // We won't know if haptic channels are available until loading the media player,
-                // and since the media player needs to be reset to change audio attributes, then
-                // we proactively enable the channels - it won't matter if they aren't present.
-                if (!mUseExactAudioAttributes) {
-                    boolean shouldBeMuted = effectiveHapticGenerator || !hapticChannelsSupported;
-                    if (shouldBeMuted != hapticChannelsMuted) {
-                        effectiveAudioAttributes =
-                                new AudioAttributes.Builder(effectiveAudioAttributes)
-                                .setHapticChannelsMuted(shouldBeMuted)
-                                .build();
-                    }
-                }
-                // If no contextual vibration, then try loading the default one for the URI.
-                if (mVibrationEffect == null && mUri != null) {
-                    effectiveVibrationEffect = VibrationEffect.get(mUri, mContext);
-                }
-            }
+        if (mLocalPlayer != null) {
+            return mLocalPlayer.isPlaying();
+        } else if (mAllowRemote && (mRemotePlayer != null)) {
             try {
-                Ringtone ringtone = new Ringtone(this, effectiveEnabledMedia,
-                        effectiveAudioAttributes, effectiveVibrationEffect,
-                        effectiveHapticGenerator);
-                if (ringtone.reinitializeActivePlayer()) {
-                    return ringtone;
-                } else {
-                    Log.e(TAG, "Failed to open ringtone " + mUri);
-                    return null;
-                }
-            } catch (Exception ex) {
-                // Catching Exception isn't great, but was done in the old
-                // RingtoneManager.getRingtone and hides errors like DocumentsProvider throwing
-                // IllegalArgumentException instead of FileNotFoundException, and also robolectric
-                // failures when ShadowMediaPlayer wasn't pre-informed of the ringtone.
-                Log.e(TAG, "Failed while opening ringtone " + mUri, ex);
-                return null;
+                return mRemotePlayer.isPlaying(mRemoteToken);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Problem checking ringtone: " + e);
+                return false;
             }
-        }
-    }
-
-    /**
-     * Interface for intercepting static methods and constructors, for unit testing only.
-     * @hide
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public static class Injectables {
-        /** Intercept {@code new MediaPlayer()}. */
-        @NonNull
-        public MediaPlayer newMediaPlayer() {
-            return new MediaPlayer();
-        }
-
-        /** Intercept {@link HapticGenerator#isAvailable}. */
-        public boolean isHapticGeneratorAvailable() {
-            return HapticGenerator.isAvailable();
-        }
-
-        /**
-         * Intercept {@link HapticGenerator#create} using
-         * {@link MediaPlayer#getAudioSessionId()} from the given media player.
-         */
-        @Nullable
-        public HapticGenerator createHapticGenerator(@NonNull MediaPlayer mediaPlayer) {
-            return HapticGenerator.create(mediaPlayer.getAudioSessionId());
-        }
-
-        /** Returns the result of {@link AudioManager#isHapticPlaybackSupported()}. */
-        public boolean isHapticPlaybackSupported() {
-            return AudioManager.isHapticPlaybackSupported();
-        }
-
-        /**
-         * Returns whether the MediaPlayer tracks have haptic channels. This is the same as
-         * AudioManager.hasHapticChannels, except it uses an already prepared MediaPlayer to avoid
-         * loading the metadata a second time.
-         */
-        public boolean hasHapticChannels(MediaPlayer mp) {
-            try {
-                Trace.beginSection("Ringtone.hasHapticChannels");
-                for (MediaPlayer.TrackInfo trackInfo : mp.getTrackInfo()) {
-                    if (trackInfo.hasHapticChannels()) {
-                        return true;
-                    }
-                }
-            } finally {
-                Trace.endSection();
-            }
+        } else {
+            Log.w(TAG, "Neither local nor remote playback available");
             return false;
         }
-
     }
 
-    /**
-     * 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();
+    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;
+    }
+
+    void setTitle(String title) {
+        mTitle = title;
+    }
+
+    @Override
+    protected void finalize() {
+        if (mLocalPlayer != null) {
+            mLocalPlayer.release();
+        }
+    }
+
+    class MyOnCompletionListener implements MediaPlayer.OnCompletionListener {
+        @Override
+        public void onCompletion(MediaPlayer mp) {
+            synchronized (sActiveRingtones) {
+                sActiveRingtones.remove(Ringtone.this);
+            }
+            mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle.
+        }
     }
 }
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index b5a9ae2..3432b3f 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.annotation.IntDef;
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -30,27 +30,24 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.StaleDataException;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.vibrator.Flags;
-import android.os.vibrator.persistence.VibrationXmlParser;
 import android.provider.BaseColumns;
 import android.provider.MediaStore;
 import android.provider.MediaStore.Audio.AudioColumns;
 import android.provider.MediaStore.MediaColumns;
 import android.provider.Settings;
 import android.provider.Settings.System;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.database.SortCursor;
@@ -61,8 +58,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -122,53 +117,6 @@
     public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
 
     /**
-     * Given to the ringtone picker as a string that represents the category of ringtone picker that
-     * should be used. This value should also be returned once a ringtone is selected.
-     * <p>
-     * The categories are:
-     * <li>{@link #CATEGORY_RINGTONE_PICKER_SOUND}
-     * <li>{@link #CATEGORY_RINGTONE_PICKER_VIBRATION}
-     * <li>{@link #CATEGORY_RINGTONE_PICKER_RINGTONE}
-     * <li>{@link Intent#CATEGORY_DEFAULT}
-     *
-     * <p> If the category is {@link Intent#CATEGORY_DEFAULT} or absent, then the picker will
-     * default to a sound-only ringtone picker.
-     *
-     * <p> If the selected category was not supported, then the returned category will be null.
-     *
-     * @hide
-     */
-    public static final String EXTRA_RINGTONE_PICKER_CATEGORY =
-            "android.intent.extra.ringtone.RINGTONE_PICKER_CATEGORY";
-
-    /**
-     * A sound-only ringtone picker.
-     *
-     * @hide
-     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
-     */
-    public static final String CATEGORY_RINGTONE_PICKER_SOUND =
-            "android.net.category.RINGTONE_PICKER_SOUND";
-
-    /**
-     * A vibration-only ringtone picker.
-     *
-     * @hide
-     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
-     */
-    public static final String CATEGORY_RINGTONE_PICKER_VIBRATION =
-            "android.net.category.RINGTONE_PICKER_VIBRATION";
-
-    /**
-     * A combined sound and vibration ringtone picker.
-     *
-     * @hide
-     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
-     */
-    public static final String CATEGORY_RINGTONE_PICKER_RINGTONE =
-            "android.net.category.RINGTONE_PICKER_RINGTONE";
-
-    /**
      * Given to the ringtone picker as a boolean. Whether to show an item for
      * "Default".
      * 
@@ -209,18 +157,6 @@
      */
     public static final String EXTRA_RINGTONE_EXISTING_URI =
             "android.intent.extra.ringtone.EXISTING_URI";
-
-    /**
-     * Similar to #EXTRA_RINGTONE_EXISTING_URI but the {@link Uri} can include both sound and
-     * vibration.
-     * <p>This can include silent sound/vibration explicitly by setting that part of the URI to
-     * null.
-     *
-     * @hide
-     * @see #ACTION_RINGTONE_PICKER
-     */
-    public static final String EXTRA_RINGTONE_EXISTING_RINGTONE_URI =
-            "android.intent.extra.ringtone.RINGTONE_EXISTING_RINGTONE_URI";
     
     /**
      * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
@@ -273,30 +209,21 @@
      */
     public static final String EXTRA_RINGTONE_PICKED_URI =
             "android.intent.extra.ringtone.PICKED_URI";
-
-    /**
-     * Declares the allowed types of media for this RingtoneManager.
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "MEDIA_", value = {
-            Ringtone.MEDIA_SOUND,
-            Ringtone.MEDIA_VIBRATION,
-    })
-    public @interface MediaType {}
-
+    
     // Make sure the column ordering and then ..._COLUMN_INDEX are in sync
     
-    private static final String[] MEDIA_AUDIO_COLUMNS = new String[] {
+    private static final String[] INTERNAL_COLUMNS = new String[] {
         MediaStore.Audio.Media._ID,
         MediaStore.Audio.Media.TITLE,
         MediaStore.Audio.Media.TITLE,
         MediaStore.Audio.Media.TITLE_KEY,
     };
 
-    private static final String[] MEDIA_VIBRATION_COLUMNS = new String[]{
-            MediaStore.Files.FileColumns._ID,
-            MediaStore.Files.FileColumns.TITLE,
+    private static final String[] MEDIA_COLUMNS = new String[] {
+        MediaStore.Audio.Media._ID,
+        MediaStore.Audio.Media.TITLE,
+        MediaStore.Audio.Media.TITLE,
+        MediaStore.Audio.Media.TITLE_KEY,
     };
 
     /**
@@ -324,9 +251,7 @@
     private Cursor mCursor;
 
     private int mType = TYPE_RINGTONE;
-    @MediaType
-    private int mMediaType = Ringtone.MEDIA_SOUND;
-
+    
     /**
      * If a column (item from this list) exists in the Cursor, its value must
      * be true (value of 1) for the row to be returned.
@@ -393,41 +318,6 @@
     }
 
     /**
-     * Sets the media type that will be listed by the RingtoneManager.
-     *
-     * <p>This method should be called before calling {@link RingtoneManager#getCursor()}.
-     *
-     * @hide
-     */
-    public void setMediaType(@MediaType int mediaType) {
-        if (mCursor != null) {
-            throw new IllegalStateException(
-                    "Setting media should be done before calling getCursor().");
-        }
-
-        switch (mediaType) {
-            case Ringtone.MEDIA_SOUND:
-            case Ringtone.MEDIA_VIBRATION:
-                mMediaType = mediaType;
-                break;
-            default:
-                throw new IllegalArgumentException("Unsupported media type " + mediaType);
-        }
-    }
-
-    /**
-     * Returns the RingtoneManagers media type.
-     *
-     * @return the media type.
-     * @see #setMediaType
-     * @hide
-     */
-    @MediaType
-    public int getMediaType() {
-        return mMediaType;
-    }
-
-    /**
      * Sets which type(s) of ringtones will be listed by this.
      * 
      * @param type The type(s), one or more of {@link #TYPE_RINGTONE},
@@ -465,25 +355,6 @@
         }
     }
 
-    /** @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}.
@@ -564,19 +435,19 @@
             return mCursor;
         }
 
-        ArrayList<Cursor> cursors = new ArrayList<>();
-
-        cursors.add(queryMediaStore(/* internal= */ true));
-        cursors.add(queryMediaStore(/* internal= */ false));
+        ArrayList<Cursor> ringtoneCursors = new ArrayList<Cursor>();
+        ringtoneCursors.add(getInternalRingtones());
+        ringtoneCursors.add(getMediaRingtones());
 
         if (mIncludeParentRingtones) {
             Cursor parentRingtonesCursor = getParentProfileRingtones();
             if (parentRingtonesCursor != null) {
-                cursors.add(parentRingtonesCursor);
+                ringtoneCursors.add(parentRingtonesCursor);
             }
         }
-        return mCursor = new SortCursor(cursors.toArray(new Cursor[cursors.size()]),
-                getSortOrderForMedia(mMediaType));
+
+        return mCursor = new SortCursor(ringtoneCursors.toArray(new Cursor[ringtoneCursors.size()]),
+                MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
     }
 
     private Cursor getParentProfileRingtones() {
@@ -588,7 +459,9 @@
                 // We don't need to re-add the internal ringtones for the work profile since
                 // they are the same as the personal profile. We just need the external
                 // ringtones.
-                return queryMediaStore(parentContext, /* internal= */ false);
+                final Cursor res = getMediaRingtones(parentContext);
+                return new ExternalRingtonesCursorWrapper(res, ContentProvider.maybeAddUserId(
+                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, parentInfo.id));
             }
         }
         return null;
@@ -606,32 +479,11 @@
             mPreviousRingtone.stop();
         }
 
-        Ringtone ringtone;
-        Uri positionUri = getRingtoneUri(position);
-        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
-            mPreviousRingtone = new Ringtone.Builder(
-                    mContext, mMediaType, getDefaultAudioAttributes(mType))
-                    .setUri(positionUri)
-                    .build();
-        } else {
-            mPreviousRingtone = createRingtoneV1WithStreamType(mContext, positionUri,
-                    inferStreamType(), /* volumeShaperConfig= */ null);
-        }
+        mPreviousRingtone =
+                getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true);
         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}.
      * 
@@ -783,13 +635,11 @@
      */
     public static Uri getValidRingtoneUri(Context context) {
         final RingtoneManager rm = new RingtoneManager(context);
-
-        Uri uri = getValidRingtoneUriFromCursorAndClose(context,
-                rm.queryMediaStore(/* internal= */ true));
+        
+        Uri uri = getValidRingtoneUriFromCursorAndClose(context, rm.getInternalRingtones());
 
         if (uri == null) {
-            uri = getValidRingtoneUriFromCursorAndClose(context,
-                    rm.queryMediaStore(/* internal= */ false));
+            uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones());
         }
         
         return uri;
@@ -810,26 +660,28 @@
         }
     }
 
-    private Cursor queryMediaStore(boolean internal) {
-        return queryMediaStore(mContext, internal);
+    @UnsupportedAppUsage
+    private Cursor getInternalRingtones() {
+        final Cursor res = query(
+                MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
+                constructBooleanTrueWhereClause(mFilterColumns),
+                null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
+        return new ExternalRingtonesCursorWrapper(res, MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
     }
 
-    private Cursor queryMediaStore(Context context, boolean internal) {
-        Uri contentUri = getContentUriForMedia(mMediaType, internal);
-        String[] columns =
-                mMediaType == Ringtone.MEDIA_VIBRATION ? MEDIA_VIBRATION_COLUMNS
-                        : MEDIA_AUDIO_COLUMNS;
-        String whereClause = getWhereClauseForMedia(mMediaType, mFilterColumns);
-        String sortOrder = getSortOrderForMedia(mMediaType);
+    private Cursor getMediaRingtones() {
+        final Cursor res = getMediaRingtones(mContext);
+        return new ExternalRingtonesCursorWrapper(res, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
+    }
 
-        Cursor cursor = query(contentUri, columns, whereClause, /* selectionArgs= */ null,
-                sortOrder, context);
-
-        if (context.getUserId() != mContext.getUserId()) {
-            contentUri = ContentProvider.maybeAddUserId(contentUri, context.getUserId());
-        }
-
-        return new ExternalRingtonesCursorWrapper(cursor, contentUri);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    private Cursor getMediaRingtones(Context context) {
+        // MediaStore now returns ringtones on other storage devices, even when
+        // we don't have storage or audio permissions
+        return query(
+                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
+                constructBooleanTrueWhereClause(mFilterColumns), null,
+                MediaStore.Audio.Media.DEFAULT_SORT_ORDER, context);
     }
 
     private void setFilterColumnsList(int type) {
@@ -848,56 +700,6 @@
             columns.add(MediaStore.Audio.AudioColumns.IS_ALARM);
         }
     }
-
-    /**
-     * Returns the sort order for the specified media.
-     *
-     * @param media The RingtoneManager media type.
-     * @return The sort order column.
-     */
-    private static String getSortOrderForMedia(@MediaType int media) {
-        return media == Ringtone.MEDIA_VIBRATION ? MediaStore.Files.FileColumns.TITLE
-                : MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
-    }
-
-    /**
-     * Returns the content URI based on the specified media and whether it's internal or external
-     * storage.
-     *
-     * @param media    The RingtoneManager media type.
-     * @param internal Whether it's for internal or external storage.
-     * @return The media content URI.
-     */
-    private static Uri getContentUriForMedia(@MediaType int media, boolean internal) {
-        switch (media) {
-            case Ringtone.MEDIA_VIBRATION:
-                return MediaStore.Files.getContentUri(
-                        internal ? MediaStore.VOLUME_INTERNAL : MediaStore.VOLUME_EXTERNAL);
-            case Ringtone.MEDIA_SOUND:
-                return internal ? MediaStore.Audio.Media.INTERNAL_CONTENT_URI
-                        : MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
-            default:
-                throw new IllegalArgumentException("Unsupported media type " + media);
-        }
-    }
-
-    /**
-     * Constructs a where clause based on the media type. This will be used to find all matching
-     * sound or vibration files.
-     *
-     * @param media   The RingtoneManager media type.
-     * @param columns The columns that must be true, when media type is {@link Ringtone#MEDIA_SOUND}
-     * @return The where clause.
-     */
-    private static String getWhereClauseForMedia(@MediaType int media, List<String> columns) {
-        // TODO(b/296213309): Filtering by ringtone-type isn't supported yet for vibrations.
-        if (media == Ringtone.MEDIA_VIBRATION) {
-            return TextUtils.formatSimple("(%s='%s')", MediaStore.Files.FileColumns.MIME_TYPE,
-                    VibrationXmlParser.APPLICATION_VIBRATION_XML_MIME_TYPE);
-        }
-
-        return constructBooleanTrueWhereClause(columns);
-    }
     
     /**
      * Constructs a where clause that consists of at least one column being 1
@@ -927,6 +729,14 @@
 
         return sb.toString();
     }
+    
+    private Cursor query(Uri uri,
+            String[] projection,
+            String selection,
+            String[] selectionArgs,
+            String sortOrder) {
+        return query(uri, projection, selection, selectionArgs, sortOrder, mContext);
+    }
 
     private Cursor query(Uri uri,
             String[] projection,
@@ -954,14 +764,40 @@
      * @return A {@link Ringtone} for the given URI, or null.
      */
     public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
-        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
-            return new Ringtone.Builder(
-                    context, Ringtone.MEDIA_SOUND, getDefaultAudioAttributes(-1))
-                    .setUri(ringtoneUri)
-                    .build();
-        } else {
-            return createRingtoneV1WithStreamType(context, ringtoneUri, -1, null);
-        }
+        // 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);
     }
 
     /**
@@ -970,23 +806,64 @@
     public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
             @Nullable VolumeShaper.Configuration volumeShaperConfig,
             AudioAttributes audioAttributes) {
-        // TODO: move caller(s) away from this method: inline the builder call.
-        if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
-            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);
+        // Don't set the stream type
+        Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */,
+                volumeShaperConfig, false);
+        if (ringtone != null) {
+            ringtone.setAudioAttributesField(audioAttributes);
+            if (!ringtone.createLocalMediaPlayer()) {
+                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#createLocalMediaPlayer()} 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.createLocalMediaPlayer()) {
+                    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;
     }
 
     /**
diff --git a/media/java/android/media/RingtoneV1.java b/media/java/android/media/RingtoneV1.java
deleted file mode 100644
index 3c54d4a..0000000
--- 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 f1a8155..0000000
--- 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/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index 7a329bc..1325fc1 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -22,7 +22,6 @@
         "android-ex-camera2",
         "android.media.playback.flags-aconfig-java",
         "flag-junit",
-        "testables",
         "testng",
         "truth",
     ],
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/OWNERS b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/OWNERS
deleted file mode 100644
index 6d5f82c..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Haptics team also works on Ringtone
-per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RingtoneTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RingtoneTest.java
deleted file mode 100644
index 3c0c684..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RingtoneTest.java
+++ /dev/null
@@ -1,840 +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 com.android.mediaframeworktest.unit;
-
-import static android.media.Ringtone.MEDIA_SOUND;
-import static android.media.Ringtone.MEDIA_SOUND_AND_VIBRATION;
-import static android.media.Ringtone.MEDIA_VIBRATION;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.AssetFileDescriptor;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.IRingtonePlayer;
-import android.media.MediaPlayer;
-import android.media.Ringtone;
-import android.media.audiofx.HapticGenerator;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.testing.TestableContext;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.mediaframeworktest.R;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.FileNotFoundException;
-import java.util.ArrayDeque;
-import java.util.Map;
-import java.util.Queue;
-
-@RunWith(AndroidJUnit4.class)
-public class RingtoneTest {
-
-    private static final Uri SOUND_URI = Uri.parse("content://fake-sound-uri");
-
-    private static final AudioAttributes RINGTONE_ATTRIBUTES =
-            audioAttributes(AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
-    private static final AudioAttributes RINGTONE_ATTRIBUTES_WITH_HC =
-            new AudioAttributes.Builder(RINGTONE_ATTRIBUTES).setHapticChannelsMuted(false).build();
-    private static final VibrationAttributes RINGTONE_VIB_ATTRIBUTES =
-            new VibrationAttributes.Builder(RINGTONE_ATTRIBUTES).build();
-
-    private static final VibrationEffect VIBRATION_EFFECT =
-            VibrationEffect.createWaveform(new long[] { 0, 100, 50, 100}, -1);
-    private static final VibrationEffect VIBRATION_EFFECT_REPEATING =
-            VibrationEffect.createWaveform(new long[] { 0, 100, 50, 100, 50}, 1);
-
-    @Rule
-    public final RingtoneInjectablesTrackingTestRule
-            mMediaPlayerRule = new RingtoneInjectablesTrackingTestRule();
-
-    @Captor private ArgumentCaptor<IBinder> mIBinderCaptor;
-    @Mock private IRingtonePlayer mMockRemotePlayer;
-    @Mock private Vibrator mMockVibrator;
-    private AudioManager mSpyAudioManager;
-    private TestableContext mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        TestableContext testContext =
-                new TestableContext(InstrumentationRegistry.getTargetContext(), null);
-        testContext.getTestablePermissions().setPermission(Manifest.permission.VIBRATE,
-                PackageManager.PERMISSION_GRANTED);
-        AudioManager realAudioManager = testContext.getSystemService(AudioManager.class);
-        mSpyAudioManager = spy(realAudioManager);
-        when(mSpyAudioManager.getRingtonePlayer()).thenReturn(mMockRemotePlayer);
-        testContext.addMockSystemService(AudioManager.class, mSpyAudioManager);
-        testContext.addMockSystemService(Vibrator.class, mMockVibrator);
-
-        mContext = spy(testContext);
-    }
-
-    @Test
-    public void testRingtone_fullLifecycleUsingLocalMediaPlayer() throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES).setUri(SOUND_URI).build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getAudioAttributes()).isEqualTo(RINGTONE_ATTRIBUTES);
-        assertThat(ringtone.getVolume()).isEqualTo(1.0f);
-        assertThat(ringtone.isLooping()).isEqualTo(false);
-        assertThat(ringtone.isHapticGeneratorEnabled()).isEqualTo(false);
-        assertThat(ringtone.getPreferBuiltinDevice()).isFalse();
-        assertThat(ringtone.getVolumeShaperConfig()).isNull();
-        assertThat(ringtone.isLocalOnly()).isFalse();
-
-        // Prepare
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES);
-        verify(mockMediaPlayer).setVolume(1.0f);
-        verify(mockMediaPlayer).setLooping(false);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        verifyLocalPlay(mockMediaPlayer);
-
-        // Verify dynamic controls.
-        ringtone.setVolume(0.8f);
-        verify(mockMediaPlayer).setVolume(0.8f);
-        when(mockMediaPlayer.isLooping()).thenReturn(false);
-        ringtone.setLooping(true);
-        verify(mockMediaPlayer).isLooping();
-        verify(mockMediaPlayer).setLooping(true);
-        HapticGenerator mockHapticGenerator =
-                mMediaPlayerRule.expectHapticGenerator(mockMediaPlayer);
-        ringtone.setHapticGeneratorEnabled(true);
-        verify(mockHapticGenerator).setEnabled(true);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-
-        // This test is intended to strictly verify all interactions with MediaPlayer in a local
-        // playback case. This shouldn't be necessary in other tests that have the same basic
-        // setup.
-        verifyNoMoreInteractions(mockMediaPlayer);
-        verify(mockHapticGenerator).release();
-        verifyNoMoreInteractions(mockHapticGenerator);
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyZeroInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaPlayerWithAudioCoupledOverride() throws Exception {
-        // Audio coupled playback is enabled in the incoming attributes, plus an instruction
-        // to leave the attributes alone. This test verifies that the attributes reach the
-        // media player without changing.
-        final AudioAttributes audioAttributes = RINGTONE_ATTRIBUTES_WITH_HC;
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        mMediaPlayerRule.setHasHapticChannels(mockMediaPlayer, true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND, audioAttributes)
-                        .setUri(SOUND_URI)
-                        .setUseExactAudioAttributes(true)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getAudioAttributes()).isEqualTo(audioAttributes);
-
-        // Prepare
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, audioAttributes);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        verifyLocalPlay(mockMediaPlayer);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyZeroInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_fullLifecycleUsingRemoteMediaPlayer() throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        setupFileNotFound(mockMediaPlayer, SOUND_URI);
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES)
-                .setUri(SOUND_URI)
-                .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isTrue();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getAudioAttributes()).isEqualTo(RINGTONE_ATTRIBUTES);
-        assertThat(ringtone.getVolume()).isEqualTo(1.0f);
-        assertThat(ringtone.isLooping()).isEqualTo(false);
-        assertThat(ringtone.isHapticGeneratorEnabled()).isEqualTo(false);
-        assertThat(ringtone.getPreferBuiltinDevice()).isFalse();
-        assertThat(ringtone.getVolumeShaperConfig()).isNull();
-        assertThat(ringtone.isLocalOnly()).isFalse();
-
-        // Initialization did try to create a local media player.
-        verify(mockMediaPlayer).setDataSource(mContext, SOUND_URI);
-        // setDataSource throws file not found, so nothing else will happen on the local player.
-        verify(mockMediaPlayer).release();
-
-        // Delegates to remote media player.
-        ringtone.play();
-        verify(mMockRemotePlayer).playRemoteRingtone(mIBinderCaptor.capture(), eq(SOUND_URI),
-                eq(RINGTONE_ATTRIBUTES), eq(false), eq(MEDIA_SOUND), isNull(),
-                eq(1.0f), eq(false), eq(false), isNull());
-        IBinder remoteToken = mIBinderCaptor.getValue();
-
-        // Verify dynamic controls.
-        ringtone.setVolume(0.8f);
-        verify(mMockRemotePlayer).setVolume(remoteToken, 0.8f);
-        ringtone.setLooping(true);
-        verify(mMockRemotePlayer).setLooping(remoteToken, true);
-        ringtone.setHapticGeneratorEnabled(true);
-        verify(mMockRemotePlayer).setHapticGeneratorEnabled(remoteToken, true);
-
-        ringtone.stop();
-        verify(mMockRemotePlayer).stop(remoteToken);
-        verifyNoMoreInteractions(mMockRemotePlayer);
-        verifyNoMoreInteractions(mockMediaPlayer);
-        verifyZeroInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibration() throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND_AND_VIBRATION, RINGTONE_ATTRIBUTES)
-                        .setUri(SOUND_URI)
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND_AND_VIBRATION);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Prepare
-        // Uses attributes with haptic channels enabled, but will use the effect when there aren't
-        // any present.
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC);
-        verify(mockMediaPlayer).setVolume(1.0f);
-        verify(mockMediaPlayer).setLooping(false);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-
-        verifyLocalPlay(mockMediaPlayer);
-        verify(mMockVibrator).vibrate(VIBRATION_EFFECT, RINGTONE_VIB_ATTRIBUTES);
-
-        // Verify dynamic controls.
-        ringtone.setVolume(0.8f);
-        verify(mockMediaPlayer).setVolume(0.8f);
-
-        // Set looping doesn't affect an already-started vibration.
-        when(mockMediaPlayer.isLooping()).thenReturn(false);  // Checks original
-        ringtone.setLooping(true);
-        verify(mockMediaPlayer).isLooping();
-        verify(mockMediaPlayer).setLooping(true);
-
-        // This is ignored because there's a vibration effect being used.
-        ringtone.setHapticGeneratorEnabled(true);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-        verify(mMockVibrator).cancel(VibrationAttributes.USAGE_RINGTONE);
-
-        // This test is intended to strictly verify all interactions with MediaPlayer in a local
-        // playback case. This shouldn't be necessary in other tests that have the same basic
-        // setup.
-        verifyNoMoreInteractions(mockMediaPlayer);
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyNoMoreInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibrationOnly() throws Exception {
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_VIBRATION, RINGTONE_ATTRIBUTES)
-                        // TODO: set sound uri too in diff test
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_VIBRATION);
-        assertThat(ringtone.getUri()).isNull();
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Play
-        ringtone.play();
-
-        verify(mMockVibrator).vibrate(VIBRATION_EFFECT, RINGTONE_VIB_ATTRIBUTES);
-
-        // Verify dynamic controls (no-op without sound)
-        ringtone.setVolume(0.8f);
-
-        // Set looping doesn't affect an already-started vibration.
-        ringtone.setLooping(true);
-
-        // This is ignored because there's a vibration effect being used and no sound.
-        ringtone.setHapticGeneratorEnabled(true);
-
-        // Release
-        ringtone.stop();
-        verify(mMockVibrator).cancel(VibrationAttributes.USAGE_RINGTONE);
-
-        // This test is intended to strictly verify all interactions with MediaPlayer in a local
-        // playback case. This shouldn't be necessary in other tests that have the same basic
-        // setup.
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyNoMoreInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibrationOnlyAndSoundUriNoHapticChannels()
-            throws Exception {
-        // A media player will still be created for vibration-only because the vibration can come
-        // from haptic channels on the sound file (although in this case it doesn't).
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        mMediaPlayerRule.setHasHapticChannels(mockMediaPlayer, false);
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_VIBRATION, RINGTONE_ATTRIBUTES)
-                        .setUri(SOUND_URI)
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_VIBRATION);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Prepare
-        // Uses attributes with haptic channels enabled, but will abandon the MediaPlayer when it
-        // knows there aren't any.
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC);
-        verify(mockMediaPlayer).setVolume(0.0f);  // Vibration-only: sound muted.
-        verify(mockMediaPlayer).setLooping(false);
-        verify(mockMediaPlayer).prepare();
-        verify(mockMediaPlayer).release();  // abandoned: no haptic channels.
-
-        // Play
-        ringtone.play();
-
-        verify(mMockVibrator).vibrate(VIBRATION_EFFECT, RINGTONE_VIB_ATTRIBUTES);
-
-        // Verify dynamic controls (no-op without sound)
-        ringtone.setVolume(0.8f);
-
-        // Set looping doesn't affect an already-started vibration.
-        ringtone.setLooping(true);
-
-        // This is ignored because there's a vibration effect being used and no sound.
-        ringtone.setHapticGeneratorEnabled(true);
-
-        // Release
-        ringtone.stop();
-        verify(mMockVibrator).cancel(VibrationAttributes.USAGE_RINGTONE);
-
-        // This test is intended to strictly verify all interactions with MediaPlayer in a local
-        // playback case. This shouldn't be necessary in other tests that have the same basic
-        // setup.
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyNoMoreInteractions(mMockVibrator);
-        verifyNoMoreInteractions(mockMediaPlayer);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibrationOnlyAndSoundUriWithHapticChannels()
-            throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        mMediaPlayerRule.setHasHapticChannels(mockMediaPlayer, true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_VIBRATION, RINGTONE_ATTRIBUTES)
-                        .setUri(SOUND_URI)
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_VIBRATION);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Prepare
-        // Uses attributes with haptic channels enabled, but will use the effect when there aren't
-        // any present.
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC);
-        verify(mockMediaPlayer).setVolume(0.0f);  // Vibration-only: sound muted.
-        verify(mockMediaPlayer).setLooping(false);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        // Vibrator.vibrate isn't called because the vibration comes from the sound.
-        verifyLocalPlay(mockMediaPlayer);
-
-        // Verify dynamic controls (no-op without sound)
-        ringtone.setVolume(0.8f);
-
-        when(mockMediaPlayer.isLooping()).thenReturn(false);  // Checks original
-        ringtone.setLooping(true);
-        verify(mockMediaPlayer).isLooping();
-        verify(mockMediaPlayer).setLooping(true);
-
-        // This is ignored because it's using haptic channels.
-        ringtone.setHapticGeneratorEnabled(true);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-
-        // This test is intended to strictly verify all interactions with MediaPlayer in a local
-        // playback case. This shouldn't be necessary in other tests that have the same basic
-        // setup.
-        verifyZeroInteractions(mMockRemotePlayer);
-        verifyZeroInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibrationPrefersHapticChannels() throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        mMediaPlayerRule.setHasHapticChannels(mockMediaPlayer, true);
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND_AND_VIBRATION, RINGTONE_ATTRIBUTES)
-                        .setUri(SOUND_URI)
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND_AND_VIBRATION);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Prepare
-        // The attributes here have haptic channels enabled (unlike above)
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        when(mockMediaPlayer.isPlaying()).thenReturn(true);
-        verifyLocalPlay(mockMediaPlayer);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-
-        verifyZeroInteractions(mMockRemotePlayer);
-        // Nothing after the initial hasVibrator - it uses audio-coupled.
-        verifyNoMoreInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_localMediaWithVibrationButSoundMuted() throws Exception {
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        mMediaPlayerRule.setHasHapticChannels(mockMediaPlayer, false);
-        doReturn(0).when(mSpyAudioManager)
-                .getStreamVolume(AudioAttributes.toLegacyStreamType(RINGTONE_ATTRIBUTES));
-        when(mMockVibrator.hasVibrator()).thenReturn(true);
-        Ringtone ringtone =
-                newBuilder(MEDIA_SOUND_AND_VIBRATION, RINGTONE_ATTRIBUTES)
-                        .setUri(SOUND_URI)
-                        .setVibrationEffect(VIBRATION_EFFECT)
-                        .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-        verify(mMockVibrator).hasVibrator();
-
-        // Verify all the properties.
-        assertThat(ringtone.getEnabledMedia()).isEqualTo(MEDIA_SOUND_AND_VIBRATION);
-        assertThat(ringtone.getUri()).isEqualTo(SOUND_URI);
-        assertThat(ringtone.getVibrationEffect()).isEqualTo(VIBRATION_EFFECT);
-
-        // Prepare
-        // The attributes here have haptic channels enabled (unlike above)
-        verifyLocalPlayerSetup(mockMediaPlayer, SOUND_URI, RINGTONE_ATTRIBUTES_WITH_HC);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        // The media player is never played, because sound is muted.
-        verify(mockMediaPlayer, never()).start();
-        when(mockMediaPlayer.isPlaying()).thenReturn(true);
-        verify(mMockVibrator).vibrate(VIBRATION_EFFECT, RINGTONE_VIB_ATTRIBUTES);
-
-        // Release
-        ringtone.stop();
-        verify(mockMediaPlayer).release();
-        verify(mMockVibrator).cancel(VibrationAttributes.USAGE_RINGTONE);
-
-        verifyZeroInteractions(mMockRemotePlayer);
-        // Nothing after the initial hasVibrator - it uses audio-coupled.
-        verifyNoMoreInteractions(mMockVibrator);
-    }
-
-    @Test
-    public void testRingtone_nullMediaOnBuilderUsesFallback() throws Exception {
-        AssetFileDescriptor testResourceFd =
-                mContext.getResources().openRawResourceFd(R.raw.shortmp3);
-        // Ensure it will flow as expected.
-        assertThat(testResourceFd).isNotNull();
-        assertThat(testResourceFd.getDeclaredLength()).isAtLeast(0);
-        mContext.getOrCreateTestableResources()
-                .addOverride(com.android.internal.R.raw.fallbackring, testResourceFd);
-
-        MediaPlayer mockMediaPlayer = mMediaPlayerRule.expectLocalMediaPlayer();
-        Ringtone ringtone = newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES)
-                .setUri(null)
-                .build();
-        assertThat(ringtone).isNotNull();
-        assertThat(ringtone.isUsingRemotePlayer()).isFalse();
-
-        // Delegates straight to fallback in local player.
-        // Prepare
-        verifyLocalPlayerFallbackSetup(mockMediaPlayer, testResourceFd, RINGTONE_ATTRIBUTES);
-        verify(mockMediaPlayer).setVolume(1.0f);
-        verify(mockMediaPlayer).setLooping(false);
-        verify(mockMediaPlayer).prepare();
-
-        // Play
-        ringtone.play();
-        verifyLocalPlay(mockMediaPlayer);
-
-        // Release
-        ringtone.stop();
-        verifyLocalStop(mockMediaPlayer);
-
-        verifyNoMoreInteractions(mockMediaPlayer);
-        verifyNoMoreInteractions(mMockRemotePlayer);
-    }
-
-    @Test
-    public void testRingtone_nullMediaOnBuilderUsesFallbackViaRemote() throws Exception {
-        mContext.getOrCreateTestableResources()
-                .addOverride(com.android.internal.R.raw.fallbackring, null);
-        Ringtone ringtone = newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES)
-                .setUri(null)
-                .setLooping(true) // distinct from haptic generator, to match plumbing
-                .build();
-        assertThat(ringtone).isNotNull();
-        // Local player fallback fails as the resource isn't found (no media player creation is
-        // attempted), and then goes on to create the remote player.
-        assertThat(ringtone.isUsingRemotePlayer()).isTrue();
-
-        ringtone.play();
-        verify(mMockRemotePlayer).playRemoteRingtone(mIBinderCaptor.capture(), isNull(),
-                eq(RINGTONE_ATTRIBUTES), eq(false),
-                eq(MEDIA_SOUND), isNull(),
-                eq(1.0f), eq(true), eq(false), isNull());
-        ringtone.stop();
-        verify(mMockRemotePlayer).stop(mIBinderCaptor.getValue());
-        verifyNoMoreInteractions(mMockRemotePlayer);
-    }
-
-    @Test
-    public void testRingtone_noMediaSetOnBuilderFallbackFailsAndNoRemote() throws Exception {
-        mContext.getOrCreateTestableResources()
-                .addOverride(com.android.internal.R.raw.fallbackring, null);
-        Ringtone ringtone = newBuilder(MEDIA_SOUND, RINGTONE_ATTRIBUTES)
-                .setUri(null)
-                .setLocalOnly()
-                .build();
-        // Local player fallback fails as the resource isn't found (no media player creation is
-        // attempted), and since there is no local player, the ringtone ends up having nothing to
-        // do.
-        assertThat(ringtone).isNull();
-    }
-
-    private Ringtone.Builder newBuilder(@Ringtone.RingtoneMedia int ringtoneMedia,
-            AudioAttributes audioAttributes) {
-        return new Ringtone.Builder(mContext, ringtoneMedia, audioAttributes)
-                .setInjectables(mMediaPlayerRule.injectables);
-    }
-
-    private static AudioAttributes audioAttributes(int audioUsage) {
-        return new AudioAttributes.Builder()
-                .setUsage(audioUsage)
-                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                .build();
-    }
-
-    /** Makes the mock get some sort of file access problem. */
-    private void setupFileNotFound(MediaPlayer mockMediaPlayer, Uri uri) throws Exception {
-        doThrow(new FileNotFoundException("Fake file not found"))
-                .when(mockMediaPlayer).setDataSource(any(Context.class), eq(uri));
-    }
-
-    private void verifyLocalPlayerSetup(MediaPlayer mockPlayer, Uri expectedUri,
-            AudioAttributes expectedAudioAttributes) throws Exception {
-        verify(mockPlayer).setDataSource(mContext, expectedUri);
-        verify(mockPlayer).setAudioAttributes(expectedAudioAttributes);
-        verify(mockPlayer).setPreferredDevice(null);
-        verify(mockPlayer).prepare();
-    }
-
-    private void verifyLocalPlayerFallbackSetup(MediaPlayer mockPlayer, AssetFileDescriptor afd,
-            AudioAttributes expectedAudioAttributes) throws Exception {
-        // This is very specific but it's a simple way to test that the test resource matches.
-        if (afd.getDeclaredLength() < 0) {
-            verify(mockPlayer).setDataSource(afd.getFileDescriptor());
-        } else {
-            verify(mockPlayer).setDataSource(afd.getFileDescriptor(),
-                    afd.getStartOffset(),
-                    afd.getDeclaredLength());
-        }
-        verify(mockPlayer).setAudioAttributes(expectedAudioAttributes);
-        verify(mockPlayer).setPreferredDevice(null);
-        verify(mockPlayer).prepare();
-    }
-
-    private void verifyLocalPlay(MediaPlayer mockMediaPlayer) {
-        verify(mockMediaPlayer).setOnCompletionListener(any());
-        verify(mockMediaPlayer).start();
-    }
-
-    private void verifyLocalStop(MediaPlayer mockMediaPlayer) {
-        verify(mockMediaPlayer).stop();
-        verify(mockMediaPlayer).setOnCompletionListener(isNull());
-        verify(mockMediaPlayer).reset();
-        verify(mockMediaPlayer).release();
-    }
-
-    /**
-     * This rule ensures that all expected media player creations from the factory do actually
-     * occur. The reason for this level of control is that creating a media player is fairly
-     * expensive and blocking, so we do want unit tests of this class to "declare" interactions
-     * of all created media players.
-     *
-     * This needs to be a TestRule so that the teardown assertions can be skipped if the test has
-     * failed (and media player assertions may just be a distracting side effect). Otherwise, the
-     * teardown failures hide the real test ones.
-     */
-    public static class RingtoneInjectablesTrackingTestRule implements TestRule {
-        public Ringtone.Injectables injectables = new TestInjectables();
-        public boolean hapticGeneratorAvailable = true;
-
-        // Queue of (local) media players, in order of expected creation. Enqueue using
-        // expectNewMediaPlayer(), dequeued by the media player factory passed to Ringtone.
-        // This queue is asserted to be empty at the end of the test.
-        private Queue<MediaPlayer> mMockMediaPlayerQueue = new ArrayDeque<>();
-
-        // Similar to media players, but for haptic generator, which also needs releasing.
-        private Map<MediaPlayer, HapticGenerator> mMockHapticGeneratorMap = new ArrayMap<>();
-
-        // Media players with haptic channels.
-        private ArraySet<MediaPlayer> mHapticChannels = new ArraySet<>();
-
-        @Override
-        public Statement apply(Statement base, Description description) {
-            return new Statement() {
-                @Override
-                public void evaluate() throws Throwable {
-                    base.evaluate();
-                    // Only assert if the test didn't fail (base.evaluate() would throw).
-                    assertWithMessage("Test setup an expectLocalMediaPlayer but it wasn't consumed")
-                            .that(mMockMediaPlayerQueue).isEmpty();
-                    // Only assert if the test didn't fail (base.evaluate() would throw).
-                    assertWithMessage(
-                            "Test setup an expectLocalHapticGenerator but it wasn't consumed")
-                            .that(mMockHapticGeneratorMap).isEmpty();
-                }
-            };
-        }
-
-        private TestMediaPlayer expectLocalMediaPlayer() {
-            TestMediaPlayer mockMediaPlayer = Mockito.mock(TestMediaPlayer.class);
-            // Delegate to simulated methods. This means they can be verified but also reflect
-            // realistic transitions from the TestMediaPlayer.
-            doCallRealMethod().when(mockMediaPlayer).start();
-            doCallRealMethod().when(mockMediaPlayer).stop();
-            doCallRealMethod().when(mockMediaPlayer).setLooping(anyBoolean());
-            when(mockMediaPlayer.isLooping()).thenCallRealMethod();
-            when(mockMediaPlayer.isLooping()).thenCallRealMethod();
-            mMockMediaPlayerQueue.add(mockMediaPlayer);
-            return mockMediaPlayer;
-        }
-
-        private HapticGenerator expectHapticGenerator(MediaPlayer mockMediaPlayer) {
-            HapticGenerator mockHapticGenerator = Mockito.mock(HapticGenerator.class);
-            // A test should never want this.
-            assertWithMessage("Can't expect a second haptic generator created "
-                    + "for one media player")
-                    .that(mMockHapticGeneratorMap.put(mockMediaPlayer, mockHapticGenerator))
-                    .isNull();
-            return mockHapticGenerator;
-        }
-
-        private void setHasHapticChannels(MediaPlayer mp, boolean hasHapticChannels) {
-            if (hasHapticChannels) {
-                mHapticChannels.add(mp);
-            } else {
-                mHapticChannels.remove(mp);
-            }
-        }
-
-        private class TestInjectables extends Ringtone.Injectables {
-            @Override
-            public MediaPlayer newMediaPlayer() {
-                assertWithMessage(
-                        "Unexpected MediaPlayer creation. Bug or need expectNewMediaPlayer")
-                        .that(mMockMediaPlayerQueue)
-                        .isNotEmpty();
-                return mMockMediaPlayerQueue.remove();
-            }
-
-            @Override
-            public boolean isHapticGeneratorAvailable() {
-                return hapticGeneratorAvailable;
-            }
-
-            @Override
-            public HapticGenerator createHapticGenerator(MediaPlayer mediaPlayer) {
-                HapticGenerator mockHapticGenerator = mMockHapticGeneratorMap.remove(mediaPlayer);
-                assertWithMessage("Unexpected HapticGenerator creation. "
-                        + "Bug or need expectHapticGenerator")
-                        .that(mockHapticGenerator)
-                        .isNotNull();
-                return mockHapticGenerator;
-            }
-
-            @Override
-            public boolean isHapticPlaybackSupported() {
-                return true;
-            }
-
-            @Override
-            public boolean hasHapticChannels(MediaPlayer mp) {
-                return mHapticChannels.contains(mp);
-            }
-        }
-    }
-
-    /**
-     * MediaPlayer relies on a native backend and so its necessary to intercept calls from
-     * fake usage hitting them.
-     *
-     * Mocks don't work directly on native calls, but if they're overridden then it does work.
-     * Some basic state faking is also done to make the mocks more realistic.
-     */
-    private static class TestMediaPlayer extends MediaPlayer {
-        private boolean mIsPlaying = false;
-        private boolean mIsLooping = false;
-
-        @Override
-        public void start() {
-            mIsPlaying = true;
-        }
-
-        @Override
-        public void stop() {
-            mIsPlaying = false;
-        }
-
-        @Override
-        public void setLooping(boolean value) {
-            mIsLooping = value;
-        }
-
-        @Override
-        public boolean isLooping() {
-            return mIsLooping;
-        }
-
-        @Override
-        public boolean isPlaying() {
-            return mIsPlaying;
-        }
-
-        void simulatePlayingFinished() {
-            if (!mIsPlaying) {
-                throw new IllegalStateException(
-                        "Attempted to pretend playing finished when not playing");
-            }
-            mIsPlaying = false;
-        }
-    }
-}
diff --git a/media/tests/ringtone/Android.bp b/media/tests/ringtone/Android.bp
deleted file mode 100644
index 55b98c4..0000000
--- a/media/tests/ringtone/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
-    name: "MediaRingtoneTests",
-
-    srcs: ["src/**/*.java"],
-
-    libs: [
-        "android.test.runner",
-        "android.test.base",
-    ],
-
-    static_libs: [
-        "androidx.test.rules",
-        "testng",
-        "androidx.test.ext.truth",
-        "frameworks-base-testutils",
-    ],
-
-    test_suites: [
-        "device-tests",
-        "automotive-tests",
-    ],
-
-    platform_apis: true,
-    certificate: "platform",
-}
diff --git a/media/tests/ringtone/AndroidManifest.xml b/media/tests/ringtone/AndroidManifest.xml
deleted file mode 100644
index 27eda07..0000000
--- a/media/tests/ringtone/AndroidManifest.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.framework.base.media.ringtone.tests">
-
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-
-        <activity android:name="MediaRingtoneTests"
-                  android:label="Media Ringtone Tests"
-                  android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.framework.base.media.ringtone.tests"
-                     android:label="Media Ringtone Tests"/>
-</manifest>
diff --git a/media/tests/ringtone/TEST_MAPPING b/media/tests/ringtone/TEST_MAPPING
deleted file mode 100644
index 6f25c14..0000000
--- a/media/tests/ringtone/TEST_MAPPING
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "MediaRingtoneTests",
-      "options": [
-        {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "androidx.test.filters.FlakyTest"},
-        {"exclude-annotation": "org.junit.Ignore"}
-      ]
-    }
-  ],
-  "postsubmit": [
-    {
-      "name": "MediaRingtoneTests",
-      "options": [
-        {"exclude-annotation": "org.junit.Ignore"}
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/media/tests/ringtone/res/raw/test_haptic_file.ahv b/media/tests/ringtone/res/raw/test_haptic_file.ahv
deleted file mode 100644
index d6eba1a..0000000
--- a/media/tests/ringtone/res/raw/test_haptic_file.ahv
+++ /dev/null
@@ -1,17 +0,0 @@
-<vibration-effect>
-  <waveform-effect>
-    <waveform-entry durationMs="63" amplitude="255"/>
-    <waveform-entry durationMs="63" amplitude="231"/>
-    <waveform-entry durationMs="63" amplitude="208"/>
-    <waveform-entry durationMs="63" amplitude="185"/>
-    <waveform-entry durationMs="63" amplitude="162"/>
-    <waveform-entry durationMs="63" amplitude="139"/>
-    <waveform-entry durationMs="63" amplitude="115"/>
-    <waveform-entry durationMs="63" amplitude="92"/>
-    <waveform-entry durationMs="63" amplitude="69"/>
-    <waveform-entry durationMs="63" amplitude="46"/>
-    <waveform-entry durationMs="63" amplitude="23"/>
-    <waveform-entry durationMs="63" amplitude="0"/>
-    <waveform-entry durationMs="1250" amplitude="0"/>
-  </waveform-effect>
-</vibration-effect>
diff --git a/media/tests/ringtone/res/raw/test_sound_file.mp3 b/media/tests/ringtone/res/raw/test_sound_file.mp3
deleted file mode 100644
index c1b2fdf..0000000
--- a/media/tests/ringtone/res/raw/test_sound_file.mp3
+++ /dev/null
Binary files differ
diff --git a/media/tests/ringtone/src/com/android/media/RingtoneManagerTest.java b/media/tests/ringtone/src/com/android/media/RingtoneManagerTest.java
deleted file mode 100644
index a92b298..0000000
--- a/media/tests/ringtone/src/com/android/media/RingtoneManagerTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 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 com.android.media;
-
-import static com.google.android.mms.ContentType.AUDIO_MP3;
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.os.vibrator.persistence.VibrationXmlParser;
-import android.provider.MediaStore;
-import android.text.TextUtils;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.framework.base.media.ringtone.tests.R;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(Parameterized.class)
-public class RingtoneManagerTest {
-    @RingtoneManager.MediaType
-    private final int mMediaType;
-    private final List<Uri> mAddedFilesUri;
-    private Context mContext;
-    private RingtoneManager mRingtoneManager;
-    private long mTimestamp;
-
-    @Parameterized.Parameters(name = "media = {0}")
-    public static Iterable<?> data() {
-        return Arrays.asList(Ringtone.MEDIA_SOUND, Ringtone.MEDIA_VIBRATION);
-    }
-
-    public RingtoneManagerTest(@RingtoneManager.MediaType int mediaType) {
-        mMediaType = mediaType;
-        mAddedFilesUri = new ArrayList<>();
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mTimestamp = SystemClock.uptimeMillis();
-        mRingtoneManager = new RingtoneManager(mContext);
-        mRingtoneManager.setMediaType(mMediaType);
-    }
-
-    @After
-    public void tearDown() {
-        // Clean up media store
-        for (Uri fileUri : mAddedFilesUri) {
-            mContext.getContentResolver().delete(fileUri, null);
-        }
-    }
-
-    @Test
-    public void testSetMediaType_withValidValue_setsMediaCorrectly() {
-        mRingtoneManager.setMediaType(mMediaType);
-        assertThat(mRingtoneManager.getMediaType()).isEqualTo(mMediaType);
-    }
-
-    @Test
-    public void testSetMediaType_withInvalidValue_throwsException() {
-        assertThrows(IllegalArgumentException.class, () -> mRingtoneManager.setMediaType(999));
-    }
-
-    @Test
-    public void testSetMediaType_afterCallingGetCursor_throwsException() {
-        mRingtoneManager.getCursor();
-        assertThrows(IllegalStateException.class, () -> mRingtoneManager.setMediaType(mMediaType));
-    }
-
-    @Test
-    public void testGetRingtone_ringtoneHasCorrectTitle() throws Exception {
-        String fileName = generateUniqueFileName("new_file");
-        Ringtone ringtone = addNewRingtoneToMediaStore(mRingtoneManager, fileName);
-
-        assertThat(ringtone.getTitle(mContext)).isEqualTo(fileName);
-    }
-
-    @Test
-    public void testGetRingtone_ringtoneCanBePlayedAndStopped() throws Exception {
-        //TODO(b/261571543) Remove this assumption once we support playing vibrations.
-        assumeTrue(mMediaType == Ringtone.MEDIA_SOUND);
-        String fileName = generateUniqueFileName("new_file");
-        Ringtone ringtone = addNewRingtoneToMediaStore(mRingtoneManager, fileName);
-
-        ringtone.play();
-        assertThat(ringtone.isPlaying()).isTrue();
-
-        ringtone.stop();
-        assertThat(ringtone.isPlaying()).isFalse();
-    }
-
-    @Test
-    public void testGetCursor_withDifferentMedia_returnsCorrectCursor() throws Exception {
-        RingtoneManager audioRingtoneManager = new RingtoneManager(mContext);
-        String audioFileName = generateUniqueFileName("ringtone");
-        addNewRingtoneToMediaStore(audioRingtoneManager, audioFileName);
-
-        RingtoneManager vibrationRingtoneManager = new RingtoneManager(mContext);
-        vibrationRingtoneManager.setMediaType(Ringtone.MEDIA_VIBRATION);
-        String vibrationFileName = generateUniqueFileName("vibration");
-        addNewRingtoneToMediaStore(vibrationRingtoneManager, vibrationFileName);
-
-        Cursor audioCursor = audioRingtoneManager.getCursor();
-        Cursor vibrationCursor = vibrationRingtoneManager.getCursor();
-
-        List<String> audioTitles = extractRecordTitles(audioCursor);
-        List<String> vibrationTitles = extractRecordTitles(vibrationCursor);
-
-        assertThat(audioTitles).contains(audioFileName);
-        assertThat(audioTitles).doesNotContain(vibrationFileName);
-
-        assertThat(vibrationTitles).contains(vibrationFileName);
-        assertThat(vibrationTitles).doesNotContain(audioFileName);
-    }
-
-    private List<String> extractRecordTitles(Cursor cursor) {
-        List<String> titles = new ArrayList<>();
-
-        if (cursor.moveToFirst()) {
-            do {
-                String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
-                titles.add(title);
-            } while (cursor.moveToNext());
-        }
-
-        return titles;
-    }
-
-    private Ringtone addNewRingtoneToMediaStore(RingtoneManager ringtoneManager, String fileName)
-            throws Exception {
-        Uri fileUri = ringtoneManager.getMediaType() == Ringtone.MEDIA_SOUND ? addAudioFile(
-                fileName) : addVibrationFile(fileName);
-        mAddedFilesUri.add(fileUri);
-
-        int ringtonePosition = ringtoneManager.getRingtonePosition(fileUri);
-        Ringtone ringtone = ringtoneManager.getRingtone(ringtonePosition);
-        // Validate this is the expected ringtone.
-        assertThat(ringtone.getUri()).isEqualTo(fileUri);
-        return ringtone;
-    }
-
-    private Uri addAudioFile(String fileName) throws Exception {
-        ContentResolver resolver = mContext.getContentResolver();
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, fileName + ".mp3");
-        contentValues.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_RINGTONES);
-        contentValues.put(MediaStore.Audio.Media.MIME_TYPE, AUDIO_MP3);
-        contentValues.put(MediaStore.Audio.Media.TITLE, fileName);
-        contentValues.put(MediaStore.Audio.Media.IS_RINGTONE, 1);
-
-        Uri contentUri = resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
-                contentValues);
-        writeRawDataToFile(resolver, contentUri, R.raw.test_sound_file);
-
-        return resolver.canonicalizeOrElse(contentUri);
-    }
-
-    private Uri addVibrationFile(String fileName) throws Exception {
-        ContentResolver resolver = mContext.getContentResolver();
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, fileName + ".ahv");
-        contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH,
-                Environment.DIRECTORY_DOWNLOADS);
-        contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE,
-                VibrationXmlParser.APPLICATION_VIBRATION_XML_MIME_TYPE);
-        contentValues.put(MediaStore.Files.FileColumns.TITLE, fileName);
-
-        Uri contentUri = resolver.insert(MediaStore.Files.getContentUri(MediaStore
-                .VOLUME_EXTERNAL), contentValues);
-        writeRawDataToFile(resolver, contentUri, R.raw.test_haptic_file);
-
-        return resolver.canonicalizeOrElse(contentUri);
-    }
-
-    private void writeRawDataToFile(ContentResolver resolver, Uri contentUri, int rawResource)
-            throws Exception {
-        try (ParcelFileDescriptor pfd =
-                     resolver.openFileDescriptor(contentUri, "w", null)) {
-            InputStream inputStream = mContext.getResources().openRawResource(rawResource);
-            FileOutputStream outputStream = new FileOutputStream(pfd.getFileDescriptor());
-            outputStream.write(inputStream.readAllBytes());
-
-            inputStream.close();
-            outputStream.flush();
-            outputStream.close();
-
-        } catch (Exception e) {
-            throw new Exception("Failed to write data to file", e);
-        }
-    }
-
-    private String generateUniqueFileName(String prefix) {
-        return TextUtils.formatSimple("%s_%d", prefix, mTimestamp);
-    }
-
-}
diff --git a/packages/SoundPicker/OWNERS b/packages/SoundPicker/OWNERS
deleted file mode 100644
index 5bf46e0..0000000
--- a/packages/SoundPicker/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Haptics team works on the SoundPicker
-include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/packages/SoundPicker2/Android.bp b/packages/SoundPicker2/Android.bp
deleted file mode 100644
index f4d8bf2..0000000
--- a/packages/SoundPicker2/Android.bp
+++ /dev/null
@@ -1,46 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_library {
-    name: "SoundPicker2Lib",
-    srcs: [
-        "src/**/*.java",
-    ],
-    resource_dirs: [
-        "res",
-    ],
-    static_libs: [
-        "androidx.appcompat_appcompat",
-        "hilt_android",
-        "guava",
-        "androidx.recyclerview_recyclerview",
-        "androidx-constraintlayout_constraintlayout",
-        "androidx.viewpager2_viewpager2",
-        "com.google.android.material_material",
-    ],
-}
-
-android_app {
-    name: "SoundPicker2",
-    defaults: ["platform_app_defaults"],
-    manifest: "AndroidManifest.xml",
-    static_libs: ["SoundPicker2Lib"],
-    platform_apis: true,
-    certificate: "media",
-    privileged: true,
-
-    optimize: {
-        enabled: true,
-        optimize: true,
-        shrink: true,
-        shrink_resources: true,
-        obfuscate: false,
-        proguard_compatibility: false,
-    },
-}
diff --git a/packages/SoundPicker2/AndroidManifest.xml b/packages/SoundPicker2/AndroidManifest.xml
deleted file mode 100644
index 934b003..0000000
--- a/packages/SoundPicker2/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.soundpicker"
-        android:sharedUserId="android.media">
-
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-    <uses-permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY" />
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-
-    <application
-            android:name=".RingtonePickerApplication"
-            android:allowBackup="false"
-            android:label="@string/app_label"
-            android:theme="@style/Theme.AppCompat"
-            android:supportsRtl="true">
-        <receiver android:name="RingtoneReceiver"
-                android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY"/>
-            </intent-filter>
-        </receiver>
-
-        <service android:name="RingtoneOverlayService" />
-
-        <activity android:name="RingtonePickerActivity"
-                android:theme="@style/Theme.AppCompat.Dialog"
-                android:enabled="@*android:bool/config_defaultRingtonePickerEnabled"
-                android:excludeFromRecents="true"
-                android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.RINGTONE_PICKER" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.RINGTONE_PICKER_SOUND" />
-                <category android:name="android.intent.category.RINGTONE_PICKER_VIBRATION" />
-                <category android:name="android.intent.category.RINGTONE_PICKER_RINGTONE" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/packages/SoundPicker2/OWNERS b/packages/SoundPicker2/OWNERS
deleted file mode 100644
index 5bf46e0..0000000
--- a/packages/SoundPicker2/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Haptics team works on the SoundPicker
-include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/packages/SoundPicker2/res/drawable/ic_add.xml b/packages/SoundPicker2/res/drawable/ic_add.xml
deleted file mode 100644
index 22b3fe9..0000000
--- a/packages/SoundPicker2/res/drawable/ic_add.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-    Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="?android:attr/colorAccent"
-        android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SoundPicker2/res/drawable/ic_add_padded.xml b/packages/SoundPicker2/res/drawable/ic_add_padded.xml
deleted file mode 100644
index c376867..0000000
--- a/packages/SoundPicker2/res/drawable/ic_add_padded.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-    Copyright (C) 2017 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.
--->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-        android:drawable="@drawable/ic_add"
-        android:insetTop="4dp"
-        android:insetRight="4dp"
-        android:insetBottom="4dp"
-        android:insetLeft="4dp"/>
diff --git a/packages/SoundPicker2/res/layout-watch/add_new_sound_item.xml b/packages/SoundPicker2/res/layout-watch/add_new_sound_item.xml
deleted file mode 100644
index edfc0ab..0000000
--- a/packages/SoundPicker2/res/layout-watch/add_new_sound_item.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 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.
--->
-
-<!--
-     Currently, no file manager app on watch could handle ACTION_GET_CONTENT intent.
-     Make the visibility to "gone" to prevent failures.
- -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/add_new_sound_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:text="@null"
-        android:textColor="?android:attr/colorAccent"
-        android:gravity="center_vertical"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:drawableStart="@drawable/ic_add_padded"
-        android:drawablePadding="8dp"
-        android:ellipsize="marquee"
-        android:visibility="gone" />
diff --git a/packages/SoundPicker2/res/layout-watch/radio_with_work_badge.xml b/packages/SoundPicker2/res/layout-watch/radio_with_work_badge.xml
deleted file mode 100644
index ee29a37..0000000
--- a/packages/SoundPicker2/res/layout-watch/radio_with_work_badge.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<com.android.soundpicker.CheckedListItem xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center_vertical"
-    android:background="?android:attr/selectableItemBackground"
-    >
-
-    <CheckedTextView
-        android:id="@+id/checked_text_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="?android:attr/textColorAlertDialogListItem"
-        android:gravity="center_vertical"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:drawableStart="?android:attr/listChoiceIndicatorSingle"
-        android:drawablePadding="8dp"
-        android:ellipsize="marquee"
-        android:layout_toLeftOf="@+id/work_icon"
-        android:maxLines="3" />
-
-    <ImageView
-        android:id="@id/work_icon"
-        android:layout_width="18dp"
-        android:layout_height="18dp"
-        android:layout_alignParentRight="true"
-        android:layout_centerVertical="true"
-        android:scaleType="centerCrop"
-        android:layout_marginRight="20dp" />
-</com.android.soundpicker.CheckedListItem>
diff --git a/packages/SoundPicker2/res/layout/activity_ringtone_picker.xml b/packages/SoundPicker2/res/layout/activity_ringtone_picker.xml
deleted file mode 100644
index 6fc6080..0000000
--- a/packages/SoundPicker2/res/layout/activity_ringtone_picker.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/packages/SoundPicker2/res/layout/add_new_sound_item.xml b/packages/SoundPicker2/res/layout/add_new_sound_item.xml
deleted file mode 100644
index 024b97e..0000000
--- a/packages/SoundPicker2/res/layout/add_new_sound_item.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="fill_parent"
-              android:layout_height="wrap_content"
-              android:gravity="center_vertical"
-              android:background="?android:attr/selectableItemBackground"
-              android:focusable="true"
-              android:clickable="true">
-
-    <ImageView
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_alignParentRight="true"
-        android:layout_centerVertical="true"
-        android:scaleType="centerCrop"
-        android:layout_marginRight="24dp"
-        android:layout_marginLeft="24dp"
-        android:src="@drawable/ic_add"/>
-
-    <TextView
-        android:id="@+id/add_new_sound_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall"
-        android:text="@null"
-        android:textColor="?android:attr/colorAccent"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:maxLines="3"
-        android:gravity="center_vertical"
-        android:paddingEnd="?android:attr/dialogPreferredPadding"
-        android:drawablePadding="20dp"
-        android:ellipsize="marquee"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SoundPicker2/res/layout/fragment_ringtone_picker.xml b/packages/SoundPicker2/res/layout/fragment_ringtone_picker.xml
deleted file mode 100644
index 787f92e..0000000
--- a/packages/SoundPicker2/res/layout/fragment_ringtone_picker.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<androidx.recyclerview.widget.RecyclerView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/recycler_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-/>
\ No newline at end of file
diff --git a/packages/SoundPicker2/res/layout/fragment_tabbed_dialog.xml b/packages/SoundPicker2/res/layout/fragment_tabbed_dialog.xml
deleted file mode 100644
index 7efd911..0000000
--- a/packages/SoundPicker2/res/layout/fragment_tabbed_dialog.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent">
-    <com.google.android.material.tabs.TabLayout
-            android:id="@+id/tabLayout"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-    <androidx.viewpager2.widget.ViewPager2
-            android:id="@+id/masterViewPager"
-            android:paddingTop="12dp"
-            android:paddingBottom="12dp"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SoundPicker2/res/layout/radio_with_work_badge.xml b/packages/SoundPicker2/res/layout/radio_with_work_badge.xml
deleted file mode 100644
index 36ac93e..0000000
--- a/packages/SoundPicker2/res/layout/radio_with_work_badge.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<com.android.soundpicker.CheckedListItem
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center_vertical"
-    android:background="?android:attr/selectableItemBackground"
-    android:focusable="true"
-    android:clickable="true">
-
-    <CheckedTextView
-        android:id="@+id/checked_text_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeightSmall"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="?android:attr/textColorAlertDialogListItem"
-        android:gravity="center_vertical"
-        android:paddingStart="20dp"
-        android:paddingEnd="?android:attr/dialogPreferredPadding"
-        android:drawableStart="?android:attr/listChoiceIndicatorSingle"
-        android:drawablePadding="20dp"
-        android:ellipsize="marquee"
-        android:layout_toLeftOf="@+id/work_icon"
-        android:maxLines="3"/>
-
-    <ImageView
-        android:id="@id/work_icon"
-        android:layout_width="18dp"
-        android:layout_height="18dp"
-        android:layout_alignParentRight="true"
-        android:layout_centerVertical="true"
-        android:scaleType="centerCrop"
-        android:layout_marginRight="20dp"/>
-</com.android.soundpicker.CheckedListItem>
diff --git a/packages/SoundPicker2/res/raw/default_alarm_alert.ogg b/packages/SoundPicker2/res/raw/default_alarm_alert.ogg
deleted file mode 100644
index e69de29..0000000
--- a/packages/SoundPicker2/res/raw/default_alarm_alert.ogg
+++ /dev/null
diff --git a/packages/SoundPicker2/res/raw/default_notification_sound.ogg b/packages/SoundPicker2/res/raw/default_notification_sound.ogg
deleted file mode 100644
index e69de29..0000000
--- a/packages/SoundPicker2/res/raw/default_notification_sound.ogg
+++ /dev/null
diff --git a/packages/SoundPicker2/res/raw/default_ringtone.ogg b/packages/SoundPicker2/res/raw/default_ringtone.ogg
deleted file mode 100644
index e69de29..0000000
--- a/packages/SoundPicker2/res/raw/default_ringtone.ogg
+++ /dev/null
diff --git a/packages/SoundPicker2/res/values/config.xml b/packages/SoundPicker2/res/values/config.xml
deleted file mode 100644
index 4e237a2..0000000
--- a/packages/SoundPicker2/res/values/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds.  Do not translate.
-
-     NOTE: The naming convention is "config_camelCaseValue".  -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- True if the ringtone picker should show the ok/cancel buttons. If it is not shown, the
-    ringtone will be automatically selected when the picker is closed. -->
-    <bool name="config_showOkCancelButtons">true</bool>
-</resources>
diff --git a/packages/SoundPicker2/res/values/strings.xml b/packages/SoundPicker2/res/values/strings.xml
deleted file mode 100644
index ab7b95a..0000000
--- a/packages/SoundPicker2/res/values/strings.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Choice in the ringtone picker.  If chosen, the default ringtone will be used. -->
-    <string name="ringtone_default">Default ringtone</string>
-
-    <!-- Choice in the notification sound picker.  If chosen, the default notification sound will be
-         used. -->
-    <string name="notification_sound_default">Default notification sound</string>
-
-    <!-- Choice in the alarm sound picker.  If chosen, the default alarm sound will be used. -->
-    <string name="alarm_sound_default">Default alarm sound</string>
-
-    <!-- Text for the RingtonePicker item that allows adding a new ringtone. -->
-    <string name="add_ringtone_text">Add ringtone</string>
-    <!-- Text for the RingtonePicker item that allows adding a new alarm. -->
-    <string name="add_alarm_text">Add alarm</string>
-    <!-- Text for the RingtonePicker item that allows adding a new notification. -->
-    <string name="add_notification_text">Add notification</string>
-    <!-- Text for the RingtonePicker item ContextMenu that allows deleting a custom ringtone. -->
-    <string name="delete_ringtone_text">Delete</string>
-    <!-- Text for the Toast displayed when adding a custom ringtone fails. -->
-    <string name="unable_to_add_ringtone">Unable to add custom ringtone</string>
-    <!-- Text for the Toast displayed when deleting a custom ringtone fails. -->
-    <string name="unable_to_delete_ringtone">Unable to delete custom ringtone</string>
-
-    <!-- Text for the name of the app. [CHAR LIMIT=12] -->
-    <string name="app_label">Sounds</string>
-
-    <string name="empty_list">The list is empty</string>
-    <string name="sound_page_title">Sound</string>
-    <string name="vibration_page_title">Vibration</string>
-</resources>
diff --git a/packages/SoundPicker2/res/values/styles.xml b/packages/SoundPicker2/res/values/styles.xml
deleted file mode 100644
index d22d9c4..0000000
--- a/packages/SoundPicker2/res/values/styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <style name="PickerDialogTheme" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
-    </style>
-
-</resources>
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/BasePickerFragment.java b/packages/SoundPicker2/src/com/android/soundpicker/BasePickerFragment.java
deleted file mode 100644
index 4fc2a86..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/BasePickerFragment.java
+++ /dev/null
@@ -1,312 +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 com.android.soundpicker;
-
-import android.app.Activity;
-import android.content.ContentProvider;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import dagger.hilt.android.AndroidEntryPoint;
-
-import java.util.Objects;
-
-/**
- * Base class for generic picker fragments.
- *
- * <p>This fragment displays a recycler view that is populated by a {@link RingtoneListViewAdapter}
- * with data provided by a {@link RingtoneListHandler}. Each item can be selected on click,
- * which also triggers a ringtone preview performed by the shared {@link RingtonePickerViewModel}.
- * The ringtone preview uses the selection state of all picker fragments (e.g. sound selected by
- * one fragment and vibration selected by another).
- */
-@AndroidEntryPoint(Fragment.class)
-public abstract class BasePickerFragment extends Hilt_BasePickerFragment implements
-        RingtoneListViewAdapter.Callbacks {
-
-    private static final String TAG = "BasePickerFragment";
-    private static final String COLUMN_LABEL = MediaStore.Audio.Media.TITLE;
-    private boolean mIsManagedProfile;
-    private Drawable mWorkIconDrawable;
-
-    protected RingtoneListViewAdapter mRingtoneListViewAdapter;
-    protected RecyclerView mRecyclerView;
-    protected RingtonePickerViewModel.Config mPickerConfig;
-    protected RingtonePickerViewModel mRingtonePickerViewModel;
-    protected RingtoneListHandler.Config mRingtoneListConfig;
-    protected RingtoneListHandler mRingtoneListHandler;
-
-    public BasePickerFragment() {
-        super(R.layout.fragment_ringtone_picker);
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-        mRingtonePickerViewModel = new ViewModelProvider(requireActivity()).get(
-                RingtonePickerViewModel.class);
-        mRingtoneListHandler = getRingtoneListHandler();
-        mRecyclerView = view.requireViewById(R.id.recycler_view);
-
-        mPickerConfig = mRingtonePickerViewModel.getPickerConfig();
-        mRingtoneListConfig = mRingtoneListHandler.getRingtoneListConfig();
-
-        mIsManagedProfile = UserManager.get(requireActivity()).isManagedProfile(
-                mPickerConfig.userId);
-
-        mRingtoneListViewAdapter = createRingtoneListViewAdapter();
-        mRecyclerView.setHasFixedSize(true);
-        mRecyclerView.setAdapter(mRingtoneListViewAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(requireActivity()));
-        setSelectedItem(mRingtoneListHandler.getSelectedItemPosition());
-        prepareRecyclerView(mRecyclerView);
-    }
-
-    @Override
-    public boolean isWorkRingtone(int position) {
-        if (!mIsManagedProfile) {
-            return false;
-        }
-
-        /*
-         * Display the work icon if the ringtone belongs to a work profile. We
-         * can tell that a ringtone belongs to a work profile if the picker user
-         * is a managed profile, the ringtone Uri is in external storage, and
-         * either the uri has no user id or has the id of the picker user
-         */
-        Uri currentUri = mRingtoneListHandler.getRingtoneUri(position);
-        int uriUserId = ContentProvider.getUserIdFromUri(currentUri,
-                mPickerConfig.userId);
-        Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(currentUri);
-
-        return uriUserId == mPickerConfig.userId
-                && uriWithoutUserId.toString().startsWith(
-                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString());
-    }
-
-    @Override
-    public Drawable getWorkIconDrawable() {
-        if (mWorkIconDrawable == null) {
-            mWorkIconDrawable = requireActivity().getPackageManager()
-                    .getUserBadgeForDensityNoBackground(
-                            UserHandle.of(mPickerConfig.userId), /* density= */ -1);
-        }
-
-        return mWorkIconDrawable;
-    }
-
-    @Override
-    public void onRingtoneSelected(int position) {
-        setSelectedItem(position);
-
-        // In the buttonless (watch-only) version, preemptively set our result since
-        // we won't have another chance to do so before the activity closes.
-        if (!mPickerConfig.showOkCancelButtons) {
-            setSuccessResultWithSelectedRingtone();
-        }
-
-        // Play clip
-        mRingtonePickerViewModel.playRingtone();
-    }
-
-    @Override
-    public void onAddRingtoneSelected() {
-        addRingtoneAsync();
-    }
-
-    /**
-     * Sets up the list by adding fixed items to the top and bottom, if required. And sets the
-     * selected item in the list.
-     * @param recyclerView The recyclerview that contains the list of displayed items.
-     */
-    protected void prepareRecyclerView(@NonNull RecyclerView recyclerView) {
-        // Reset the static item count, as this method can be called multiple times
-        mRingtoneListHandler.resetFixedItems();
-
-        if (mRingtoneListConfig.hasDefaultItem) {
-            int defaultItemPos = addDefaultRingtoneItem();
-
-            if (getSelectedItem() < 0
-                    && RingtoneManager.isDefault(mRingtoneListConfig.initialSelectedUri)) {
-                setSelectedItem(defaultItemPos);
-            }
-        }
-
-        if (mRingtoneListConfig.hasSilentItem) {
-            int silentItemPos = addSilentItem();
-
-            // The 'Silent' item should use a null Uri
-            if (getSelectedItem() < 0
-                    && mRingtoneListConfig.initialSelectedUri == null) {
-                setSelectedItem(silentItemPos);
-            }
-        }
-
-        if (getSelectedItem() < 0) {
-            setSelectedItem(mRingtoneListHandler.getRingtonePosition(
-                    mRingtoneListConfig.initialSelectedUri));
-        }
-
-        // In the buttonless (watch-only) version, preemptively set our result since we won't
-        // have another chance to do so before the activity closes.
-        if (!mPickerConfig.showOkCancelButtons) {
-            setSuccessResultWithSelectedRingtone();
-        }
-
-        addNewRingtoneItem();
-
-        // Enable context menu in ringtone items
-        registerForContextMenu(recyclerView);
-    }
-
-    /**
-     * Returns the fragment's sound/vibration list handler.
-     * @return The ringtone list handler.
-     */
-    protected abstract RingtoneListHandler getRingtoneListHandler();
-
-    /**
-     * Starts the process to add a new ringtone to the list of ringtones asynchronously.
-     * Currently, only works for adding sound files.
-     */
-    protected abstract void addRingtoneAsync();
-
-    /**
-     * Adds an item to the end of the list that can be used to add new ringtones to the list.
-     * Currently, only works for adding sound files.
-     */
-    protected abstract void addNewRingtoneItem();
-
-    protected int getSelectedItem() {
-        return mRingtoneListHandler.getSelectedItemPosition();
-    }
-
-    /**
-     * Returns the selected URI to the caller activity.
-     */
-    protected void setSuccessResultWithSelectedRingtone() {
-        requireActivity().setResult(Activity.RESULT_OK,
-                new Intent().putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
-                        mRingtonePickerViewModel.getSelectedRingtoneUri()));
-    }
-
-    /**
-     * Creates a ringtone recyclerview adapter using the ringtone manager cursor.
-     * @return The created RingtoneListViewAdapter.
-     */
-    protected RingtoneListViewAdapter createRingtoneListViewAdapter() {
-        LocalizedCursor cursor = new LocalizedCursor(
-                mRingtoneListHandler.getRingtoneCursor(), getResources(), COLUMN_LABEL);
-        return new RingtoneListViewAdapter(cursor, /* RingtoneListViewAdapterCallbacks= */ this);
-    }
-
-    /**
-     * Sets the selected item in the list and scroll to the position in the recyclerview.
-     * @param pos the position of the selected item in the list.
-     */
-    protected void setSelectedItem(int pos) {
-        Objects.requireNonNull(mRingtoneListViewAdapter);
-        mRingtoneListHandler.setSelectedItemPosition(pos);
-        mRingtoneListViewAdapter.setSelectedItem(pos);
-        mRingtoneListHandler.setSelectedItemId(mRingtoneListViewAdapter.getItemId(pos));
-        mRecyclerView.scrollToPosition(pos);
-    }
-
-    /**
-     * Adds a fixed item to the fixed items list . A fixed item is one that is not from
-     * the RingtoneManager.
-     *
-     * @param textResId The resource ID of the text for the item.
-     * @return The index of the inserted fixed item in the adapter.
-     */
-    protected int addFixedItem(int textResId) {
-        return mRingtoneListViewAdapter.addTitleForFixedItem(textResId);
-    }
-
-    /**
-     * Re-query RingtoneManager for the most recent set of installed ringtones. May move the
-     * selected item position to match the new position of the chosen ringtone.
-     * <p>
-     * This should only need to happen after adding or removing a ringtone.
-     */
-    protected void requeryForAdapter() {
-        mRingtonePickerViewModel.reinit();
-        // Refresh and set a new cursor, and closing the old one.
-        mRingtoneListViewAdapter = createRingtoneListViewAdapter();
-        mRecyclerView.setAdapter(mRingtoneListViewAdapter);
-        prepareRecyclerView(mRecyclerView);
-
-        // Update selected item location.
-        for (int i = 0; i < mRingtoneListViewAdapter.getItemCount(); i++) {
-            if (mRingtoneListViewAdapter.getItemId(i)
-                    == mRingtoneListHandler.getSelectedItemId()) {
-                setSelectedItem(i);
-                return;
-            }
-        }
-
-        // If selected item is still unknown, then set it to the default item, if available.
-        // If it's not available, then attempt to set it to the silent item in the list.
-        int selectedPosition = mRingtoneListHandler.getDefaultItemPosition();
-
-        if (selectedPosition < 0) {
-            selectedPosition = mRingtoneListHandler.getSilentItemPosition();
-        }
-
-        setSelectedItem(selectedPosition);
-    }
-
-    private int addDefaultRingtoneItem() {
-        int defaultItemPosInAdapter = addFixedItem(
-                RingtonePickerViewModel.getDefaultRingtoneItemTextByType(
-                        mPickerConfig.ringtoneType));
-        int defaultItemPosInListHandler = mRingtoneListHandler.addDefaultItem();
-
-        if (defaultItemPosInAdapter != defaultItemPosInListHandler) {
-            Log.wtf(TAG, "Default item position in adapter and list handler must match.");
-            return RingtoneListHandler.ITEM_POSITION_UNKNOWN;
-        }
-
-        return defaultItemPosInListHandler;
-    }
-
-    private int addSilentItem() {
-        int silentItemPosInAdapter = addFixedItem(com.android.internal.R.string.ringtone_silent);
-        int silentItemPosInListHandler = mRingtoneListHandler.addSilentItem();
-
-        if (silentItemPosInAdapter != silentItemPosInListHandler) {
-            Log.wtf(TAG, "Silent item position in adapter and list handler must match.");
-            return RingtoneListHandler.ITEM_POSITION_UNKNOWN;
-        }
-
-        return silentItemPosInListHandler;
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/CheckedListItem.java b/packages/SoundPicker2/src/com/android/soundpicker/CheckedListItem.java
deleted file mode 100644
index 819ae98..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/CheckedListItem.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.android.soundpicker;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.Checkable;
-import android.widget.CheckedTextView;
-import android.widget.RelativeLayout;
-
-/**
- * The {@link CheckedListItem} is a layout item that represents a ringtone, and is used in
- * {@link RingtonePickerActivity}. It contains the ringtone's name, and a work badge to right of the
- * name if the ringtone belongs to a work profile.
- */
-public class CheckedListItem extends RelativeLayout implements Checkable {
-
-    public CheckedListItem(Context context) {
-        super(context);
-    }
-
-    public CheckedListItem(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public CheckedListItem(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public CheckedListItem(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        getCheckedTextView().setChecked(checked);
-    }
-
-    @Override
-    public boolean isChecked() {
-        return getCheckedTextView().isChecked();
-    }
-
-    @Override
-    public void toggle() {
-        getCheckedTextView().toggle();
-    }
-
-    private CheckedTextView getCheckedTextView() {
-        return (CheckedTextView) findViewById(R.id.checked_text_view);
-    }
-
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/ListeningExecutorServiceFactory.java b/packages/SoundPicker2/src/com/android/soundpicker/ListeningExecutorServiceFactory.java
deleted file mode 100644
index afdbf05..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/ListeningExecutorServiceFactory.java
+++ /dev/null
@@ -1,44 +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 com.android.soundpicker;
-
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.concurrent.Executors;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A factory class used to create {@link ListeningExecutorService}.
- */
-@Singleton
-public class ListeningExecutorServiceFactory {
-
-    @Inject
-    ListeningExecutorServiceFactory() {
-    }
-
-    /**
-     * Returns a single thread {@link ListeningExecutorService}.
-     *
-     */
-    public ListeningExecutorService createSingleThreadExecutor() {
-        return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/LocalizedCursor.java b/packages/SoundPicker2/src/com/android/soundpicker/LocalizedCursor.java
deleted file mode 100644
index 83d04a3..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/LocalizedCursor.java
+++ /dev/null
@@ -1,117 +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 com.android.soundpicker;
-
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.CursorWrapper;
-import android.util.Log;
-import android.util.TypedValue;
-
-import androidx.annotation.Nullable;
-
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-/**
- * A cursor wrapper class mainly used to guarantee getting a ringtone title
- */
-final class LocalizedCursor extends CursorWrapper {
-
-    private static final String TAG = "LocalizedCursor";
-    private static final String SOUND_NAME_RES_PREFIX = "sound_name_";
-
-    private final int mTitleIndex;
-    private final Resources mResources;
-    private final Pattern mSanitizePattern;
-    private final String mNamePrefix;
-
-    LocalizedCursor(Cursor cursor, Resources resources, String columnLabel) {
-        super(cursor);
-        mTitleIndex = mCursor.getColumnIndex(columnLabel);
-        mResources = resources;
-        mSanitizePattern = Pattern.compile("[^a-zA-Z0-9]");
-        if (mTitleIndex == -1) {
-            Log.e(TAG, "No index for column " + columnLabel);
-            mNamePrefix = null;
-        } else {
-            mNamePrefix = buildNamePrefix(mResources);
-        }
-    }
-
-    /**
-     * Builds the prefix for the name of the resource to look up.
-     * The format is: "ResourcePackageName::ResourceTypeName/" (the type name is expected to be
-     * "string" but let's not hardcode it).
-     * Here we use an existing resource "notification_sound_default" which is always expected to be
-     * found.
-     *
-     * @param resources Application's resources
-     * @return the built name prefix, or null if failed to build.
-     */
-    @Nullable
-    private static String buildNamePrefix(Resources resources) {
-        try {
-            return String.format("%s:%s/%s",
-                    resources.getResourcePackageName(R.string.notification_sound_default),
-                    resources.getResourceTypeName(R.string.notification_sound_default),
-                    SOUND_NAME_RES_PREFIX);
-        } catch (Resources.NotFoundException e) {
-            Log.e(TAG, "Failed to build the prefix for the name of the resource.", e);
-        }
-
-        return null;
-    }
-
-    /**
-     * Process resource name to generate a valid resource name.
-     *
-     * @return a non-null String
-     */
-    private String sanitize(String input) {
-        if (input == null) {
-            return "";
-        }
-        return mSanitizePattern.matcher(input).replaceAll("_").toLowerCase(Locale.ROOT);
-    }
-
-    @Override
-    public String getString(int columnIndex) {
-        final String defaultName = mCursor.getString(columnIndex);
-        if ((columnIndex != mTitleIndex) || (mNamePrefix == null)) {
-            return defaultName;
-        }
-        TypedValue value = new TypedValue();
-        try {
-            // the name currently in the database is used to derive a name to match
-            // against resource names in this package
-            mResources.getValue(mNamePrefix + sanitize(defaultName), value,
-                    /* resolveRefs= */ false);
-        } catch (Resources.NotFoundException e) {
-            Log.d(TAG, "Failed to get localized string. Using default string instead.", e);
-            return defaultName;
-        }
-        if ((value != null) && (value.type == TypedValue.TYPE_STRING)) {
-            Log.d(TAG, String.format("Replacing name %s with %s",
-                    defaultName, value.string.toString()));
-            return value.string.toString();
-        } else {
-            Log.e(TAG, "Invalid value when looking up localized name, using " + defaultName);
-            return defaultName;
-        }
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java
deleted file mode 100644
index 6817f53..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneFactory.java
+++ /dev/null
@@ -1,60 +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 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;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A factory class used to create {@link Ringtone}.
- */
-@Singleton
-public class RingtoneFactory {
-
-    private final Context mApplicationContext;
-
-    @Inject
-    RingtoneFactory(@ApplicationContext Context applicationContext) {
-        mApplicationContext = applicationContext;
-    }
-
-    /**
-     * Returns a {@link Ringtone} built from the provided URI and audio attributes flags.
-     *
-     * @param uri The URI used to build the {@link Ringtone}.
-     * @param audioAttributesFlags A combination of audio attribute flags that affect the volume
-     *                             and settings when playing the ringtone.
-     * @return the built {@link Ringtone}.
-     */
-    public Ringtone create(Uri uri, int audioAttributesFlags) {
-        AudioAttributes audioAttributes = new AudioAttributes.Builder()
-                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                .setFlags(audioAttributesFlags)
-                .build();
-        return RingtoneManager.getRingtone(mApplicationContext, uri,
-                /* volumeShaperConfig= */ null, audioAttributes);
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListHandler.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListHandler.java
deleted file mode 100644
index bb38e0e..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListHandler.java
+++ /dev/null
@@ -1,222 +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 com.android.soundpicker;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.Nullable;
-import android.database.Cursor;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import javax.inject.Inject;
-
-/**
- * Handles ringtone list state and actions. This includes keeping track of the selected item,
- * ringtone manager cursor and added items to the list.
- */
-public class RingtoneListHandler {
-
-    // TODO: We're using an empty URI instead of null, because null URIs still produce a sound,
-    //  while empty ones don't (Potentially this might be due to empty URIs being perceived as
-    //  malformed ones). We will switch to using the official silent URIs (SOUND_OFF, VIBRATION_OFF)
-    //  once they become available.
-    static final Uri SILENT_URI = Uri.EMPTY;
-    static final int ITEM_POSITION_UNKNOWN = -1;
-
-    private static final String TAG = "RingtoneListHandler";
-
-    /** The position in the list of the 'Silent' item. */
-    private int mSilentItemPosition = ITEM_POSITION_UNKNOWN;
-    /** The position in the list of the 'Default' item. */
-    private int mDefaultItemPosition = ITEM_POSITION_UNKNOWN;
-    /** The number of fixed items in the list. */
-    private int mFixedItemCount;
-    /**
-     * Stable ID for the ringtone that is currently selected (may be -1 if no ringtone is selected).
-     */
-    private long mSelectedItemId = -1;
-    private int mSelectedItemPosition = ITEM_POSITION_UNKNOWN;
-
-    private RingtoneManager mRingtoneManager;
-    private Config mRingtoneListConfig;
-    private Cursor mRingtoneCursor;
-
-    /**
-     * Holds immutable info on the ringtone list that is displayed.
-     */
-    static final class Config {
-        /**
-         * Whether this list has the 'Default' item.
-         */
-        public final boolean hasDefaultItem;
-        /**
-         * The Uri to play when the 'Default' item is clicked.
-         */
-        public final Uri uriForDefaultItem;
-        /**
-         * Whether this list has the 'Silent' item.
-         */
-        public final boolean hasSilentItem;
-        /**
-         * The initially selected uri in the list.
-         */
-        public final Uri initialSelectedUri;
-
-        Config(boolean hasDefaultItem, Uri uriForDefaultItem, boolean hasSilentItem,
-                Uri initialSelectedUri) {
-            this.hasDefaultItem = hasDefaultItem;
-            this.uriForDefaultItem = uriForDefaultItem;
-            this.hasSilentItem = hasSilentItem;
-            this.initialSelectedUri = initialSelectedUri;
-        }
-    }
-
-    @Inject
-    RingtoneListHandler() {
-    }
-
-    void init(@NonNull Config ringtoneListConfig,
-            @NonNull RingtoneManager ringtoneManager, @NonNull Cursor ringtoneCursor) {
-        mRingtoneManager = requireNonNull(ringtoneManager);
-        mRingtoneListConfig = requireNonNull(ringtoneListConfig);
-        mRingtoneCursor = requireNonNull(ringtoneCursor);
-    }
-
-    Config getRingtoneListConfig() {
-        return mRingtoneListConfig;
-    }
-
-    Cursor getRingtoneCursor() {
-        requireInitCalled();
-        return mRingtoneCursor;
-    }
-
-    Uri getRingtoneUri(int position) {
-        if (position < 0) {
-            Log.w(TAG, "Selected item position is unknown.");
-            // When the selected item is ITEM_POSITION_UNKNOWN, it is not the case we expected.
-            // We return SILENT_URI for this case.
-            return SILENT_URI;
-        } else if (position == mDefaultItemPosition) {
-            // Use the default Uri that they originally gave us.
-            return mRingtoneListConfig.uriForDefaultItem;
-        } else if (position == mSilentItemPosition) {
-            // Use SILENT_URI for the 'Silent' item.
-            return SILENT_URI;
-        } else {
-            requireInitCalled();
-            return mRingtoneManager.getRingtoneUri(mapListPositionToRingtonePosition(position));
-        }
-    }
-
-    int getRingtonePosition(Uri uri) {
-        requireInitCalled();
-        return mapRingtonePositionToListPosition(mRingtoneManager.getRingtonePosition(uri));
-    }
-
-    void resetFixedItems() {
-        mFixedItemCount = 0;
-        mDefaultItemPosition = ITEM_POSITION_UNKNOWN;
-        mSilentItemPosition = ITEM_POSITION_UNKNOWN;
-    }
-
-    int addDefaultItem() {
-        if (mDefaultItemPosition < 0) {
-            mDefaultItemPosition = addFixedItem();
-        }
-        return mDefaultItemPosition;
-    }
-
-    int getDefaultItemPosition() {
-        return mDefaultItemPosition;
-    }
-
-    int addSilentItem() {
-        if (mSilentItemPosition < 0) {
-            mSilentItemPosition = addFixedItem();
-        }
-        return mSilentItemPosition;
-    }
-
-    public int getSilentItemPosition() {
-        return mSilentItemPosition;
-    }
-
-    int getSelectedItemPosition() {
-        return mSelectedItemPosition;
-    }
-
-    void setSelectedItemPosition(int selectedItemPosition) {
-        mSelectedItemPosition = selectedItemPosition;
-    }
-
-    void setSelectedItemId(long selectedItemId) {
-        mSelectedItemId = selectedItemId;
-    }
-
-    long getSelectedItemId() {
-        return mSelectedItemId;
-    }
-
-    @Nullable
-    Uri getSelectedRingtoneUri() {
-        return getRingtoneUri(mSelectedItemPosition);
-    }
-
-    /**
-     * Maps the item position in the list, to its equivalent position in the RingtoneManager.
-     *
-     * @param itemPosition the position of item in the list.
-     * @return position of the item in the RingtoneManager.
-     */
-    private int mapListPositionToRingtonePosition(int itemPosition) {
-        // If the manager position is less than add items, then return that.
-        if (itemPosition < mFixedItemCount) return itemPosition;
-
-        return itemPosition - mFixedItemCount;
-    }
-
-    /**
-     * Maps the item position in the RingtoneManager, to its equivalent position in the list.
-     *
-     * @param itemPosition the position of the item in the RingtoneManager.
-     * @return position of the item in the list.
-     */
-    private int mapRingtonePositionToListPosition(int itemPosition) {
-        // If the manager position is less than add items, then return that.
-        if (itemPosition < 0) return itemPosition;
-
-        return itemPosition + mFixedItemCount;
-    }
-
-    /**
-     * Increments the number of added fixed items and returns the index of the newest added item.
-     * @return index of the newest added fixed item.
-     */
-    private int addFixedItem() {
-        return mFixedItemCount++;
-    }
-
-    private void requireInitCalled() {
-        requireNonNull(mRingtoneManager);
-        requireNonNull(mRingtoneCursor);
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListViewAdapter.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListViewAdapter.java
deleted file mode 100644
index 4ca8943..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneListViewAdapter.java
+++ /dev/null
@@ -1,264 +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 com.android.soundpicker;
-
-import static com.android.internal.widget.RecyclerView.NO_ID;
-
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.media.RingtoneManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckedTextView;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.StringRes;
-import androidx.recyclerview.widget.RecyclerView;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * The adapter presents a list of ringtones which may include fixed item in the list and an action
- * button at the end.
- *
- * The adapter handles three different types of items:
- * <ul>
- * <li>FIXED: Fixed items are items added to the top of the list. These items can not be modified
- * and their position will never change.
- * <li>DYNAMIC: Dynamic items are items from the ringtone manager. These items can be modified
- * and their position can change.
- * <li>FOOTER: A footer item is an added button to the end of the list. This item can be clicked
- * but not selected and its position will never change.
- * </ul>
- */
-final class RingtoneListViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
-
-    private static final int VIEW_TYPE_FIXED_ITEM = 0;
-    private static final int VIEW_TYPE_DYNAMIC_ITEM = 1;
-    private static final int VIEW_TYPE_ADD_RINGTONE_ITEM = 2;
-    private final Cursor mCursor;
-    private final List<Integer> mFixedItemTitles;
-    private final Callbacks mCallbacks;
-    private final int mRowIDColumn;
-    private int mSelectedItem = -1;
-    @StringRes private Integer mAddRingtoneItemTitle;
-
-    /** Provides callbacks for the adapter. */
-    interface Callbacks {
-        void onRingtoneSelected(int position);
-        void onAddRingtoneSelected();
-        boolean isWorkRingtone(int position);
-        Drawable getWorkIconDrawable();
-    }
-
-    RingtoneListViewAdapter(Cursor cursor,
-            Callbacks callbacks) {
-        mCursor = cursor;
-        mCallbacks = callbacks;
-        mFixedItemTitles = new ArrayList<>();
-        mRowIDColumn = mCursor != null ? mCursor.getColumnIndex("_id") : -1;
-        setHasStableIds(true);
-    }
-
-    void setSelectedItem(int position) {
-        notifyItemChanged(mSelectedItem);
-        mSelectedItem = position;
-        notifyItemChanged(mSelectedItem);
-    }
-
-    /**
-     * Adds title to the fixed items list and returns the index of the newest added item.
-     * @param textResId the title to add to the fixed items list.
-     * @return The index of the newest added item in the fixed items list.
-     */
-    int addTitleForFixedItem(@StringRes int textResId) {
-        mFixedItemTitles.add(textResId);
-        notifyItemInserted(mFixedItemTitles.size() - 1);
-        return mFixedItemTitles.size() - 1;
-    }
-
-    void addTitleForAddRingtoneItem(@StringRes int textResId) {
-        mAddRingtoneItemTitle = textResId;
-        notifyItemInserted(getItemCount() - 1);
-    }
-
-    @NotNull
-    @Override
-    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-
-        if (viewType == VIEW_TYPE_FIXED_ITEM) {
-            View fixedItemView = inflater.inflate(
-                    com.android.internal.R.layout.select_dialog_singlechoice_material, parent,
-                    false);
-
-            return new FixedItemViewHolder(fixedItemView, mCallbacks);
-        }
-
-        if (viewType == VIEW_TYPE_ADD_RINGTONE_ITEM) {
-            View addRingtoneItemView = inflater.inflate(R.layout.add_new_sound_item, parent, false);
-
-            return new AddRingtoneItemViewHolder(addRingtoneItemView,
-                    mCallbacks);
-        }
-
-        View view = inflater.inflate(R.layout.radio_with_work_badge, parent, false);
-
-        return new DynamicItemViewHolder(view, mCallbacks);
-    }
-
-    @Override
-    public void onBindViewHolder(@NotNull RecyclerView.ViewHolder holder, int position) {
-        if (holder instanceof FixedItemViewHolder) {
-            FixedItemViewHolder viewHolder = (FixedItemViewHolder) holder;
-
-            viewHolder.onBind(mFixedItemTitles.get(position),
-                    /* isChecked= */ position == mSelectedItem);
-            return;
-        }
-        if (holder instanceof AddRingtoneItemViewHolder) {
-            AddRingtoneItemViewHolder viewHolder = (AddRingtoneItemViewHolder) holder;
-
-            viewHolder.onBind(mAddRingtoneItemTitle);
-            return;
-        }
-
-        if (!(holder instanceof DynamicItemViewHolder)) {
-            throw new IllegalArgumentException("holder type is not supported");
-        }
-
-        DynamicItemViewHolder viewHolder = (DynamicItemViewHolder) holder;
-        int pos = position - mFixedItemTitles.size();
-        if (!mCursor.moveToPosition(pos)) {
-            throw new IllegalStateException("Could not move cursor to position: " + pos);
-        }
-
-        Drawable workIcon = (mCallbacks != null)
-                && mCallbacks.isWorkRingtone(position)
-                ? mCallbacks.getWorkIconDrawable() : null;
-
-        viewHolder.onBind(mCursor.getString(RingtoneManager.TITLE_COLUMN_INDEX),
-                /* isChecked= */ position == mSelectedItem, workIcon);
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        if (!mFixedItemTitles.isEmpty() && position < mFixedItemTitles.size()) {
-            return VIEW_TYPE_FIXED_ITEM;
-        }
-        if (mAddRingtoneItemTitle != null && position == getItemCount() - 1) {
-            return VIEW_TYPE_ADD_RINGTONE_ITEM;
-        }
-
-        return VIEW_TYPE_DYNAMIC_ITEM;
-    }
-
-    @Override
-    public int getItemCount() {
-        int itemCount = mFixedItemTitles.size() + mCursor.getCount();
-
-        if (mAddRingtoneItemTitle != null) {
-            itemCount++;
-        }
-
-        return itemCount;
-    }
-
-    @Override
-    public long getItemId(int position) {
-        int itemViewType = getItemViewType(position);
-        if (itemViewType == VIEW_TYPE_FIXED_ITEM) {
-            // Since the item is a fixed item, then we can use the position as a stable ID
-            // since the order of the fixed items should never change.
-            return position;
-        }
-        if (itemViewType == VIEW_TYPE_DYNAMIC_ITEM && mCursor != null
-                && mCursor.moveToPosition(position - mFixedItemTitles.size())
-                && mRowIDColumn != -1) {
-            return mCursor.getLong(mRowIDColumn) + mFixedItemTitles.size();
-        }
-
-        // The position is either invalid or the item is the add ringtone item view, so no stable
-        // ID is returned. Add ringtone item view cannot be selected and only include an action
-        // buttons.
-        return NO_ID;
-    }
-
-    private static class DynamicItemViewHolder extends RecyclerView.ViewHolder {
-        private final CheckedTextView mTitleTextView;
-        private final ImageView mWorkIcon;
-
-        DynamicItemViewHolder(View itemView, Callbacks listener) {
-            super(itemView);
-
-            mTitleTextView = itemView.requireViewById(R.id.checked_text_view);
-            mWorkIcon = itemView.requireViewById(R.id.work_icon);
-            itemView.setOnClickListener(v -> listener.onRingtoneSelected(this.getLayoutPosition()));
-        }
-
-        void onBind(String title, boolean isChecked, Drawable workIcon) {
-            mTitleTextView.setText(title);
-            mTitleTextView.setChecked(isChecked);
-
-            if (workIcon == null) {
-                mWorkIcon.setVisibility(View.GONE);
-            } else {
-                mWorkIcon.setImageDrawable(workIcon);
-                mWorkIcon.setVisibility(View.VISIBLE);
-            }
-        }
-    }
-
-    private static class FixedItemViewHolder extends RecyclerView.ViewHolder {
-        private final CheckedTextView mTitleTextView;
-
-        FixedItemViewHolder(View itemView, Callbacks listener) {
-            super(itemView);
-
-            mTitleTextView = (CheckedTextView) itemView;
-            itemView.setOnClickListener(v -> listener.onRingtoneSelected(this.getLayoutPosition()));
-        }
-
-        void onBind(@StringRes int title, boolean isChecked) {
-            Objects.requireNonNull(mTitleTextView);
-
-            mTitleTextView.setText(title);
-            mTitleTextView.setChecked(isChecked);
-        }
-    }
-
-    private static class AddRingtoneItemViewHolder extends RecyclerView.ViewHolder {
-        private final TextView mTitleTextView;
-
-        AddRingtoneItemViewHolder(View itemView, Callbacks listener) {
-            super(itemView);
-
-            mTitleTextView = itemView.requireViewById(R.id.add_new_sound_text);
-            itemView.setOnClickListener(v -> listener.onAddRingtoneSelected());
-        }
-
-        void onBind(@StringRes int title) {
-            mTitleTextView.setText(title);
-        }
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneManagerFactory.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneManagerFactory.java
deleted file mode 100644
index f08eb24..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneManagerFactory.java
+++ /dev/null
@@ -1,49 +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 com.android.soundpicker;
-
-import android.content.Context;
-import android.media.RingtoneManager;
-
-import dagger.hilt.android.qualifiers.ApplicationContext;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A factory class used to create {@link RingtoneManager}.
- */
-@Singleton
-public class RingtoneManagerFactory {
-
-    private final Context mApplicationContext;
-
-    @Inject
-    RingtoneManagerFactory(@ApplicationContext Context applicationContext) {
-        mApplicationContext = applicationContext;
-    }
-
-    /**
-     * Creates a new {@link RingtoneManager} and returns it.
-     *
-     * @return a {@link RingtoneManager}
-     */
-    public RingtoneManager create() {
-        return new RingtoneManager(mApplicationContext, /* includeParentRingtones */ true);
-    }
-}
-
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneOverlayService.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneOverlayService.java
deleted file mode 100644
index b94ebeb..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneOverlayService.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.soundpicker;
-
-import android.app.Service;
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.IBinder;
-import android.provider.MediaStore;
-import android.provider.Settings.System;
-import android.util.Log;
-
-import androidx.annotation.IdRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Service to copy and set customization of default sounds
- */
-public class RingtoneOverlayService extends Service {
-    private static final String TAG = "RingtoneOverlayService";
-    private static final boolean DEBUG = false;
-
-    @Override
-    public int onStartCommand(@Nullable final Intent intent, final int flags, final int startId) {
-        AsyncTask.execute(() -> {
-            updateRingtones();
-            stopSelf();
-        });
-
-        // Try again later if we are killed before we finish.
-        return Service.START_REDELIVER_INTENT;
-    }
-
-    @Override
-    public IBinder onBind(@Nullable final Intent intent) {
-        return null;
-    }
-
-    private void updateRingtones() {
-        copyResourceAndSetAsSound(R.raw.default_ringtone,
-                System.RINGTONE, Environment.DIRECTORY_RINGTONES);
-        copyResourceAndSetAsSound(R.raw.default_notification_sound,
-                System.NOTIFICATION_SOUND, Environment.DIRECTORY_NOTIFICATIONS);
-        copyResourceAndSetAsSound(R.raw.default_alarm_alert,
-                System.ALARM_ALERT, Environment.DIRECTORY_ALARMS);
-    }
-
-    /* If the resource contains any data, copy a resource to the file system, scan it, and set the
-     * file URI as the default for a sound. */
-    private void copyResourceAndSetAsSound(@IdRes final int id, @NonNull final String name,
-            @NonNull final String subPath) {
-        final File destDir = Environment.getExternalStoragePublicDirectory(subPath);
-        if (!destDir.exists() && !destDir.mkdirs()) {
-            Log.e(TAG, "can't create " + destDir.getAbsolutePath());
-            return;
-        }
-
-        final File dest = new File(destDir, "default_" + name + ".ogg");
-        try (
-                InputStream is = getResources().openRawResource(id);
-                FileOutputStream os = new FileOutputStream(dest);
-        ) {
-            if (is.available() > 0) {
-                FileUtils.copy(is, os);
-                final Uri uri = scanFile(dest);
-                if (uri != null) {
-                    set(name, uri);
-                }
-            } else {
-                // TODO Shall we remove any former copied resource in this case and unset
-                // the defaults if we use this event a second time to clear the data?
-                if (DEBUG) Log.d(TAG, "Resource for " + name + " has no overlay");
-            }
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to open resource for " + name + ": " + e);
-        }
-    }
-
-    private Uri scanFile(@NonNull final File file) {
-        return MediaStore.scanFile(getContentResolver(), file);
-    }
-
-    private void set(@NonNull final String name, @NonNull final Uri uri) {
-        final Uri settingUri = System.getUriFor(name);
-        RingtoneManager.setActualDefaultRingtoneUri(this,
-                RingtoneManager.getDefaultType(settingUri), uri);
-        System.putInt(getContentResolver(), name + "_set", 1);
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerActivity.java
deleted file mode 100644
index 90a14f9..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerActivity.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.soundpicker;
-
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.lifecycle.ViewModelProvider;
-
-import dagger.hilt.android.AndroidEntryPoint;
-
-/**
- * The {@link RingtonePickerActivity} allows the user to choose one from all of the
- * available ringtones. The chosen ringtone's URI will be persisted as a string.
- *
- * @see RingtoneManager#ACTION_RINGTONE_PICKER
- */
-@AndroidEntryPoint(AppCompatActivity.class)
-public final class RingtonePickerActivity extends Hilt_RingtonePickerActivity {
-
-    private static final String TAG = "RingtonePickerActivity";
-    // TODO: Use the extra keys from RingtoneManager once they're added.
-    private static final String EXTRA_RINGTONE_PICKER_CATEGORY = "EXTRA_RINGTONE_PICKER_CATEGORY";
-    private static final String EXTRA_VIBRATION_SHOW_DEFAULT = "EXTRA_VIBRATION_SHOW_DEFAULT";
-    private static final String EXTRA_VIBRATION_DEFAULT_URI = "EXTRA_VIBRATION_DEFAULT_URI";
-    private static final String EXTRA_VIBRATION_SHOW_SILENT = "EXTRA_VIBRATION_SHOW_SILENT";
-    private static final String EXTRA_VIBRATION_EXISTING_URI = "EXTRA_VIBRATION_EXISTING_URI";
-    private static final boolean RINGTONE_PICKER_CATEGORY_FEATURE_ENABLED = false;
-
-    private RingtonePickerViewModel mRingtonePickerViewModel;
-    private int mAttributesFlags;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_ringtone_picker);
-
-        mRingtonePickerViewModel = new ViewModelProvider(this).get(RingtonePickerViewModel.class);
-
-        Intent intent = getIntent();
-        /**
-         * Id of the user to which the ringtone picker should list the ringtones
-         */
-        int pickerUserId = UserHandle.myUserId();
-
-        // Get the types of ringtones to show
-        int ringtoneType = intent.getIntExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
-                RingtonePickerViewModel.RINGTONE_TYPE_UNKNOWN);
-
-        // AudioAttributes flags
-        mAttributesFlags |= intent.getIntExtra(
-                RingtoneManager.EXTRA_RINGTONE_AUDIO_ATTRIBUTES_FLAGS,
-                0 /*defaultValue == no flags*/);
-
-        boolean showOkCancelButtons = getResources().getBoolean(R.bool.config_showOkCancelButtons);
-
-        String title = intent.getStringExtra(RingtoneManager.EXTRA_RINGTONE_TITLE);
-        if (title == null) {
-            title = getString(RingtonePickerViewModel.getTitleByType(ringtoneType));
-        }
-        String ringtonePickerCategory = intent.getStringExtra(EXTRA_RINGTONE_PICKER_CATEGORY);
-        RingtonePickerViewModel.PickerType pickerType = mapCategoryToPickerType(
-                ringtonePickerCategory);
-
-        RingtoneListHandler.Config soundListConfig = getSoundListConfig(pickerType, intent,
-                ringtoneType);
-        RingtoneListHandler.Config vibrationListConfig = getVibrationListConfig(pickerType, intent);
-
-        RingtonePickerViewModel.Config pickerConfig =
-                new RingtonePickerViewModel.Config(title, pickerUserId, ringtoneType,
-                        showOkCancelButtons, mAttributesFlags, pickerType);
-
-        mRingtonePickerViewModel.init(pickerConfig, soundListConfig, vibrationListConfig);
-
-        if (savedInstanceState == null) {
-            TabbedDialogFragment dialogFragment = new TabbedDialogFragment();
-
-            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-            Fragment prev = getSupportFragmentManager().findFragmentByTag(TabbedDialogFragment.TAG);
-            if (prev != null) {
-                ft.remove(prev);
-            }
-            ft.addToBackStack(null);
-            dialogFragment.show(ft, TabbedDialogFragment.TAG);
-        }
-
-        // The volume keys will control the stream that we are choosing a ringtone for
-        setVolumeControlStream(mRingtonePickerViewModel.getRingtoneStreamType());
-    }
-
-    private RingtoneListHandler.Config getSoundListConfig(
-            RingtonePickerViewModel.PickerType pickerType, Intent intent, int ringtoneType) {
-        if (pickerType != RingtonePickerViewModel.PickerType.SOUND_PICKER
-                && pickerType != RingtonePickerViewModel.PickerType.RINGTONE_PICKER) {
-            // This ringtone picker does not require a sound picker.
-            return null;
-        }
-
-        // Get whether to show the 'Default' sound item, and the URI to play when it's clicked
-        boolean hasDefaultSoundItem =
-                intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
-
-        // The Uri to play when the 'Default' sound item is clicked.
-        Uri uriForDefaultSoundItem =
-                intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI);
-        if (uriForDefaultSoundItem == null) {
-            uriForDefaultSoundItem = RingtonePickerViewModel.getDefaultItemUriByType(ringtoneType);
-        }
-
-        // Get whether this list has the 'Silent' sound item.
-        boolean hasSilentSoundItem =
-                intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
-
-        // AudioAttributes flags
-        mAttributesFlags |= intent.getIntExtra(
-                RingtoneManager.EXTRA_RINGTONE_AUDIO_ATTRIBUTES_FLAGS,
-                0 /*defaultValue == no flags*/);
-
-        // Get the sound URI whose list item should have a checkmark
-        Uri existingSoundUri = intent
-                .getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
-
-        return new RingtoneListHandler.Config(hasDefaultSoundItem,
-                uriForDefaultSoundItem, hasSilentSoundItem, existingSoundUri);
-    }
-
-    private RingtoneListHandler.Config getVibrationListConfig(
-            RingtonePickerViewModel.PickerType pickerType, Intent intent) {
-        if (pickerType != RingtonePickerViewModel.PickerType.VIBRATION_PICKER
-                && pickerType != RingtonePickerViewModel.PickerType.RINGTONE_PICKER) {
-            // This ringtone picker does not require a vibration picker.
-            return null;
-        }
-
-        // Get whether to show the 'Default' vibration item, and the URI to play when it's clicked
-        boolean hasDefaultVibrationItem =
-                intent.getBooleanExtra(EXTRA_VIBRATION_SHOW_DEFAULT, false);
-
-        // The Uri to play when the 'Default' vibration item is clicked.
-        Uri uriForDefaultVibrationItem = intent.getParcelableExtra(EXTRA_VIBRATION_DEFAULT_URI);
-
-        // Get whether this list has the 'Silent' vibration item.
-        boolean hasSilentVibrationItem =
-                intent.getBooleanExtra(EXTRA_VIBRATION_SHOW_SILENT, true);
-
-        // Get the vibration URI whose list item should have a checkmark
-        Uri existingVibrationUri = intent.getParcelableExtra(EXTRA_VIBRATION_EXISTING_URI);
-
-        return new RingtoneListHandler.Config(
-                hasDefaultVibrationItem, uriForDefaultVibrationItem, hasSilentVibrationItem,
-                existingVibrationUri);
-    }
-
-    @Override
-    public void onDestroy() {
-        mRingtonePickerViewModel.cancelPendingAsyncTasks();
-        super.onDestroy();
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        mRingtonePickerViewModel.onStop(isChangingConfigurations());
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mRingtonePickerViewModel.onPause(isChangingConfigurations());
-    }
-
-    /**
-     * Maps the ringtone picker category to the appropriate PickerType.
-     * If the category is null or the feature is still not released, then it defaults to sound
-     * picker.
-     *
-     * @param category the ringtone picker category.
-     * @return the corresponding picker type.
-     */
-    private static RingtonePickerViewModel.PickerType mapCategoryToPickerType(String category) {
-        if (category == null || !RINGTONE_PICKER_CATEGORY_FEATURE_ENABLED) {
-            return RingtonePickerViewModel.PickerType.SOUND_PICKER;
-        }
-
-        switch (category) {
-            case "android.intent.category.RINGTONE_PICKER_RINGTONE":
-                return RingtonePickerViewModel.PickerType.RINGTONE_PICKER;
-            case "android.intent.category.RINGTONE_PICKER_SOUND":
-                return RingtonePickerViewModel.PickerType.SOUND_PICKER;
-            case "android.intent.category.RINGTONE_PICKER_VIBRATION":
-                return RingtonePickerViewModel.PickerType.VIBRATION_PICKER;
-            default:
-                Log.w(TAG, "Unrecognized category: " + category + ". Defaulting to sound picker.");
-                return RingtonePickerViewModel.PickerType.SOUND_PICKER;
-        }
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerApplication.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerApplication.java
deleted file mode 100644
index 48fd4fe..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerApplication.java
+++ /dev/null
@@ -1,28 +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 com.android.soundpicker;
-
-import android.app.Application;
-
-import dagger.hilt.android.HiltAndroidApp;
-
-/**
- * The main application class for the project.
- */
-@HiltAndroidApp(Application.class)
-public class RingtonePickerApplication extends Hilt_RingtonePickerApplication {
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerViewModel.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerViewModel.java
deleted file mode 100644
index 2c09711..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtonePickerViewModel.java
+++ /dev/null
@@ -1,340 +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 com.android.soundpicker;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.provider.Settings;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.ViewModel;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-
-import dagger.hilt.android.lifecycle.HiltViewModel;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * A view model which holds immutable info about the picker state and means to retrieve and play
- * currently selected ringtones.
- */
-@HiltViewModel
-public final class RingtonePickerViewModel extends ViewModel {
-
-    static final int RINGTONE_TYPE_UNKNOWN = -1;
-
-    /**
-     * Keep the currently playing ringtone around when changing orientation, so that it
-     * can be stopped later, after the activity is recreated.
-     */
-    @VisibleForTesting
-    static Ringtone sPlayingRingtone;
-
-    private static final String TAG = "RingtonePickerViewModel";
-
-    private final RingtoneManagerFactory mRingtoneManagerFactory;
-    private final RingtoneFactory mRingtoneFactory;
-    private final RingtoneListHandler mSoundListHandler;
-    private final RingtoneListHandler mVibrationListHandler;
-    private final ListeningExecutorService mListeningExecutorService;
-
-    private RingtoneManager mRingtoneManager;
-
-    /**
-     * The ringtone that's currently playing.
-     */
-    private Ringtone mCurrentRingtone;
-
-    private Config mPickerConfig;
-
-    private ListenableFuture<Uri> mAddCustomRingtoneFuture;
-
-    public enum PickerType {
-        RINGTONE_PICKER,
-        SOUND_PICKER,
-        VIBRATION_PICKER
-    }
-
-    /**
-     * Holds immutable info on the picker that should be displayed.
-     */
-    static final class Config {
-        public final String title;
-        /**
-         * Id of the user to which the ringtone picker should list the ringtones.
-         */
-        public final int userId;
-        /**
-         * Ringtone type.
-         */
-        public final int ringtoneType;
-        /**
-         * AudioAttributes flags.
-         */
-        public final int audioAttributesFlags;
-        /**
-         * In the buttonless (watch-only) version we don't show the OK/Cancel buttons.
-         */
-        public final boolean showOkCancelButtons;
-
-        public final PickerType mPickerType;
-
-        Config(String title, int userId, int ringtoneType, boolean showOkCancelButtons,
-                int audioAttributesFlags, PickerType pickerType) {
-            this.title = title;
-            this.userId = userId;
-            this.ringtoneType = ringtoneType;
-            this.showOkCancelButtons = showOkCancelButtons;
-            this.audioAttributesFlags = audioAttributesFlags;
-            this.mPickerType = pickerType;
-        }
-    }
-
-    @Inject
-    RingtonePickerViewModel(RingtoneManagerFactory ringtoneManagerFactory,
-            RingtoneFactory ringtoneFactory,
-            ListeningExecutorServiceFactory listeningExecutorServiceFactory,
-            RingtoneListHandler soundListHandler,
-            RingtoneListHandler vibrationListHandler) {
-        mRingtoneManagerFactory = ringtoneManagerFactory;
-        mRingtoneFactory = ringtoneFactory;
-        mListeningExecutorService = listeningExecutorServiceFactory.createSingleThreadExecutor();
-        mSoundListHandler = soundListHandler;
-        mVibrationListHandler = vibrationListHandler;
-    }
-
-    @StringRes
-    static int getTitleByType(int ringtoneType) {
-        switch (ringtoneType) {
-            case RingtoneManager.TYPE_ALARM:
-                return com.android.internal.R.string.ringtone_picker_title_alarm;
-            case RingtoneManager.TYPE_NOTIFICATION:
-                return com.android.internal.R.string.ringtone_picker_title_notification;
-            default:
-                return com.android.internal.R.string.ringtone_picker_title;
-        }
-    }
-
-    static Uri getDefaultItemUriByType(int ringtoneType) {
-        switch (ringtoneType) {
-            case RingtoneManager.TYPE_ALARM:
-                return Settings.System.DEFAULT_ALARM_ALERT_URI;
-            case RingtoneManager.TYPE_NOTIFICATION:
-                return Settings.System.DEFAULT_NOTIFICATION_URI;
-            default:
-                return Settings.System.DEFAULT_RINGTONE_URI;
-        }
-    }
-
-    @StringRes
-    static int getAddNewItemTextByType(int ringtoneType) {
-        switch (ringtoneType) {
-            case RingtoneManager.TYPE_ALARM:
-                return R.string.add_alarm_text;
-            case RingtoneManager.TYPE_NOTIFICATION:
-                return R.string.add_notification_text;
-            default:
-                return R.string.add_ringtone_text;
-        }
-    }
-
-    @StringRes
-    static int getDefaultRingtoneItemTextByType(int ringtoneType) {
-        switch (ringtoneType) {
-            case RingtoneManager.TYPE_ALARM:
-                return R.string.alarm_sound_default;
-            case RingtoneManager.TYPE_NOTIFICATION:
-                return R.string.notification_sound_default;
-            default:
-                return R.string.ringtone_default;
-        }
-    }
-
-    void init(@NonNull Config pickerConfig,
-            RingtoneListHandler.Config soundListConfig,
-            RingtoneListHandler.Config vibrationListConfig) {
-        mRingtoneManager = mRingtoneManagerFactory.create();
-        mPickerConfig = pickerConfig;
-        if (mPickerConfig.ringtoneType != RINGTONE_TYPE_UNKNOWN) {
-            mRingtoneManager.setType(mPickerConfig.ringtoneType);
-        }
-        if (soundListConfig != null) {
-            mSoundListHandler.init(soundListConfig, mRingtoneManager,
-                    mRingtoneManager.getCursor());
-        }
-        if (vibrationListConfig != null) {
-            // TODO: Switch to the vibration cursor, once the API is made available.
-            mVibrationListHandler.init(vibrationListConfig, mRingtoneManager,
-                    mRingtoneManager.getCursor());
-        }
-    }
-
-    /**
-     * Re-initializes the view model which is required after updating any of the picker lists.
-     * This could happen when adding a custom ringtone.
-     */
-    void reinit() {
-        init(mPickerConfig, mSoundListHandler.getRingtoneListConfig(),
-                mVibrationListHandler.getRingtoneListConfig());
-    }
-
-    @NonNull
-    Config getPickerConfig() {
-        requireInitCalled();
-        return mPickerConfig;
-    }
-
-    @NonNull
-    RingtoneListHandler getSoundListHandler() {
-        return mSoundListHandler;
-    }
-
-    @NonNull
-    RingtoneListHandler getVibrationListHandler() {
-        return mVibrationListHandler;
-    }
-
-    /**
-     * Combined the currently selected sound and vibration URIs and returns a unified URI. If the
-     * picker does not show either sound or vibration, that portion of the URI will be null.
-     *
-     * Currently only the sound URI is returned, since we don't have the API to retrieve vibrations
-     * yet.
-     * @return Combined sound and vibration URI.
-     */
-    Uri getSelectedRingtoneUri() {
-        // TODO: Combine sound and vibration URIs before returning.
-        return mSoundListHandler.getSelectedRingtoneUri();
-    }
-
-    int getRingtoneStreamType() {
-        requireInitCalled();
-        return mRingtoneManager.inferStreamType();
-    }
-
-    void onPause(boolean isChangingConfigurations) {
-        if (!isChangingConfigurations) {
-            stopAnyPlayingRingtone();
-        }
-    }
-
-    void onStop(boolean isChangingConfigurations) {
-        if (isChangingConfigurations) {
-            saveAnyPlayingRingtone();
-        } else {
-            stopAnyPlayingRingtone();
-        }
-    }
-
-    /**
-     * Plays a ringtone which is created using the currently selected sound and vibration URIs. If
-     * this is a sound or vibration only picker, then the other portion of the URI will be empty
-     * and should not affect the played ringtone.
-     *
-     * Currently, we only use the sound URI to create the ringtone, since we still don't have the
-     * API to retrieve the available vibrations list.
-     */
-    void playRingtone() {
-        requireInitCalled();
-        stopAnyPlayingRingtone();
-
-        mCurrentRingtone = mRingtoneFactory.create(getSelectedRingtoneUri(),
-                mPickerConfig.audioAttributesFlags);
-
-        if (mCurrentRingtone != null) {
-            mCurrentRingtone.play();
-        }
-    }
-
-    /**
-     * Cancels all pending async tasks.
-     */
-    void cancelPendingAsyncTasks() {
-        if (mAddCustomRingtoneFuture != null && !mAddCustomRingtoneFuture.isDone()) {
-            mAddCustomRingtoneFuture.cancel(/* mayInterruptIfRunning= */ true);
-        }
-    }
-
-    /**
-     * Adds an audio file to the list of ringtones asynchronously.
-     * Any previous async tasks are canceled before start the new one.
-     *
-     * @param uri      Uri of the file to be added as ringtone. Must be a media file.
-     * @param type     The type of the ringtone to be added.
-     * @param callback The callback to invoke when the task is completed.
-     * @param executor The executor to run the callback on when the task completes.
-     */
-    void addSoundRingtoneAsync(Uri uri, int type, FutureCallback<Uri> callback, Executor executor) {
-        // Cancel any currently running add ringtone tasks before starting a new one
-        cancelPendingAsyncTasks();
-        mAddCustomRingtoneFuture = mListeningExecutorService.submit(
-                () -> addRingtone(uri, type));
-        Futures.addCallback(mAddCustomRingtoneFuture, callback, executor);
-    }
-
-    /**
-     * Adds an audio file to the list of ringtones.
-     *
-     * @param uri  Uri of the file to be added as ringtone. Must be a media file.
-     * @param type The type of the ringtone to be added.
-     * @return The Uri of the installed ringtone, which may be the {@code uri} if it
-     * is already in ringtone storage. Or null if it failed to add the audio file.
-     */
-    @Nullable
-    private Uri addRingtone(Uri uri, int type) throws IOException {
-        requireInitCalled();
-        return mRingtoneManager.addCustomExternalRingtone(uri, type);
-    }
-
-    private void saveAnyPlayingRingtone() {
-        if (mCurrentRingtone != null && mCurrentRingtone.isPlaying()) {
-            sPlayingRingtone = mCurrentRingtone;
-        }
-        mCurrentRingtone = null;
-    }
-
-    private void stopAnyPlayingRingtone() {
-        if (sPlayingRingtone != null && sPlayingRingtone.isPlaying()) {
-            sPlayingRingtone.stop();
-        }
-        sPlayingRingtone = null;
-
-        if (mCurrentRingtone != null && mCurrentRingtone.isPlaying()) {
-            mCurrentRingtone.stop();
-        }
-        mCurrentRingtone = null;
-    }
-
-    private void requireInitCalled() {
-        requireNonNull(mRingtoneManager);
-        requireNonNull(mPickerConfig);
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneReceiver.java b/packages/SoundPicker2/src/com/android/soundpicker/RingtoneReceiver.java
deleted file mode 100644
index 6a34936..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/RingtoneReceiver.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.soundpicker;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class RingtoneReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (Intent.ACTION_DEVICE_CUSTOMIZATION_READY.equals(action)) {
-            initResourceRingtones(context);
-        }
-    }
-
-    private void initResourceRingtones(Context context) {
-        context.startService(
-                new Intent(context, RingtoneOverlayService.class));
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/SoundPickerFragment.java b/packages/SoundPicker2/src/com/android/soundpicker/SoundPickerFragment.java
deleted file mode 100644
index a37191f..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/SoundPickerFragment.java
+++ /dev/null
@@ -1,122 +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 com.android.soundpicker;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-import androidx.activity.result.ActivityResult;
-import androidx.activity.result.ActivityResultCallback;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.core.content.ContextCompat;
-import androidx.lifecycle.ViewModelProvider;
-
-import com.google.common.util.concurrent.FutureCallback;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A fragment that displays a picker used to select sound or silent. It also includes the
- * ability to add custom sounds.
- */
-public class SoundPickerFragment extends BasePickerFragment {
-
-    private static final String TAG = "SoundPickerFragment";
-
-    private final FutureCallback<Uri> mAddCustomRingtoneCallback = new FutureCallback<>() {
-        @Override
-        public void onSuccess(Uri ringtoneUri) {
-            requeryForAdapter();
-        }
-
-        @Override
-        public void onFailure(Throwable throwable) {
-            Log.e(TAG, "Failed to add custom ringtone.", throwable);
-            // Ringtone was not added, display error Toast
-            Toast.makeText(requireActivity().getApplicationContext(),
-                    R.string.unable_to_add_ringtone, Toast.LENGTH_SHORT).show();
-        }
-    };
-
-    ActivityResultLauncher<Intent> mActivityResultLauncher = registerForActivityResult(
-            new ActivityResultContracts.StartActivityForResult(),
-            new ActivityResultCallback<ActivityResult>() {
-                @Override
-                public void onActivityResult(ActivityResult result) {
-                    if (result.getResultCode() == Activity.RESULT_OK) {
-                        // There are no request codes
-                        Intent data = result.getData();
-                        mRingtonePickerViewModel.addSoundRingtoneAsync(data.getData(),
-                                mPickerConfig.ringtoneType,
-                                mAddCustomRingtoneCallback,
-                                // Causes the callback to be executed on the main thread.
-                                ContextCompat.getMainExecutor(
-                                        requireActivity().getApplicationContext()));
-                    }
-                }
-            });
-
-    @Override
-    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
-        mRingtonePickerViewModel = new ViewModelProvider(requireActivity()).get(
-                RingtonePickerViewModel.class);
-        super.onViewCreated(view, savedInstanceState);
-    }
-
-    @Override
-    protected RingtoneListHandler getRingtoneListHandler() {
-        return mRingtonePickerViewModel.getSoundListHandler();
-    }
-
-    @Override
-    protected void addRingtoneAsync() {
-        // The "Add new ringtone" item was clicked. Start a file picker intent to
-        // select only audio files (MIME type "audio/*")
-        final Intent chooseFile = getMediaFilePickerIntent();
-        mActivityResultLauncher.launch(chooseFile);
-    }
-
-    @Override
-    protected void addNewRingtoneItem() {
-        // If external storage is available, add a button to install sounds from storage.
-        if (resolvesMediaFilePicker()
-                && Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            mRingtoneListViewAdapter.addTitleForAddRingtoneItem(
-                    RingtonePickerViewModel.getAddNewItemTextByType(mPickerConfig.ringtoneType));
-        }
-    }
-
-    private boolean resolvesMediaFilePicker() {
-        return getMediaFilePickerIntent().resolveActivity(requireActivity().getPackageManager())
-                != null;
-    }
-
-    private Intent getMediaFilePickerIntent() {
-        final Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
-        chooseFile.setType("audio/*");
-        chooseFile.putExtra(Intent.EXTRA_MIME_TYPES,
-                new String[]{"audio/*", "application/ogg"});
-        return chooseFile;
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/TabbedDialogFragment.java b/packages/SoundPicker2/src/com/android/soundpicker/TabbedDialogFragment.java
deleted file mode 100644
index 50ea9d7..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/TabbedDialogFragment.java
+++ /dev/null
@@ -1,180 +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 com.android.soundpicker;
-
-import static android.app.Activity.RESULT_CANCELED;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-import dagger.hilt.android.AndroidEntryPoint;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A dialog fragment with a sound and/or vibration tab based on the picker type.
- * <ul>
- * <li> Ringtone Pickers will display both sound and vibration tabs.
- * <li> Sound Pickers will only display the sound tab.
- * <li> Vibration Pickers will only display the vibration tab.
- * </ul>
- */
-@AndroidEntryPoint(DialogFragment.class)
-public class TabbedDialogFragment extends Hilt_TabbedDialogFragment {
-
-    static final String TAG = "TabbedDialogFragment";
-
-    private RingtonePickerViewModel mRingtonePickerViewModel;
-
-    private final ViewPager2.OnPageChangeCallback mOnPageChangeCallback =
-            new ViewPager2.OnPageChangeCallback() {
-                @Override
-                public void onPageScrollStateChanged(int state) {
-                    super.onPageScrollStateChanged(state);
-                    if (state == ViewPager2.SCROLL_STATE_IDLE) {
-                        mRingtonePickerViewModel.onStop(/* isChangingConfigurations= */ false);
-                    }
-                }
-            };
-
-    @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mRingtonePickerViewModel = new ViewModelProvider(requireActivity()).get(
-                RingtonePickerViewModel.class);
-    }
-
-    @NonNull
-    @Override
-    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity(),
-                android.R.style.ThemeOverlay_Material_Dialog)
-                .setTitle(mRingtonePickerViewModel.getPickerConfig().title);
-        // Do not show OK/Cancel buttons in the buttonless (watch-only) version.
-        if (mRingtonePickerViewModel.getPickerConfig().showOkCancelButtons) {
-            dialogBuilder
-                    .setPositiveButton(getString(com.android.internal.R.string.ok),
-                            (dialog, whichButton) -> {
-                                setSuccessResultWithSelectedRingtone();
-                                requireActivity().finish();
-                            })
-                    .setNegativeButton(getString(com.android.internal.R.string.cancel),
-                            (dialog, whichButton) -> {
-                                requireActivity().setResult(RESULT_CANCELED);
-                                requireActivity().finish();
-                            });
-        }
-
-        View view = buildTabbedView(requireActivity().getLayoutInflater());
-        dialogBuilder.setView(view);
-
-        return dialogBuilder.create();
-    }
-
-    @Override
-    public void onCancel(@NonNull @NotNull DialogInterface dialog) {
-        super.onCancel(dialog);
-        if (!requireActivity().isChangingConfigurations()) {
-            requireActivity().finish();
-        }
-    }
-
-    @Override
-    public void onDismiss(@NonNull @NotNull DialogInterface dialog) {
-        super.onDismiss(dialog);
-        if (!requireActivity().isChangingConfigurations()) {
-            requireActivity().finish();
-        }
-    }
-
-    private void setSuccessResultWithSelectedRingtone() {
-        requireActivity().setResult(Activity.RESULT_OK,
-                new Intent().putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
-                        mRingtonePickerViewModel.getSelectedRingtoneUri()));
-    }
-
-    /**
-     * Inflates the tabbed layout view and adds the required fragments. If there's only one
-     * fragment to display, then the tab area is hidden.
-     * @param inflater The LayoutInflater that is used to inflate the tabbed view.
-     * @return The tabbed view.
-     */
-    private View buildTabbedView(@NonNull LayoutInflater inflater) {
-        View view = inflater.inflate(R.layout.fragment_tabbed_dialog, null, false);
-        TabLayout tabLayout = view.requireViewById(R.id.tabLayout);
-        ViewPager2 viewPager = view.requireViewById(R.id.masterViewPager);
-
-        ViewPagerAdapter adapter = new ViewPagerAdapter(requireActivity());
-        addFragments(adapter);
-
-        if (adapter.getItemCount() == 1) {
-            // Hide the tab area since there's only one fragment to display.
-            tabLayout.setVisibility(View.GONE);
-        }
-
-        viewPager.setAdapter(adapter);
-        viewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
-        new TabLayoutMediator(tabLayout, viewPager,
-                (tab, position) -> tab.setText(adapter.getTitle(position))).attach();
-
-        return view;
-    }
-
-    /**
-     * Adds the appropriate fragments to the adapter based on the PickerType.
-     *
-     * @param adapter The adapter to add the fragments to.
-     */
-    private void addFragments(ViewPagerAdapter adapter) {
-        switch (mRingtonePickerViewModel.getPickerConfig().mPickerType) {
-            case RINGTONE_PICKER:
-                adapter.addFragment(getString(R.string.sound_page_title),
-                        new SoundPickerFragment());
-                adapter.addFragment(getString(R.string.vibration_page_title),
-                        new VibrationPickerFragment());
-                break;
-            case SOUND_PICKER:
-                adapter.addFragment(getString(R.string.sound_page_title),
-                        new SoundPickerFragment());
-                break;
-            case VIBRATION_PICKER:
-                adapter.addFragment(getString(R.string.vibration_page_title),
-                        new VibrationPickerFragment());
-                break;
-            default:
-                adapter.addFragment(getString(R.string.sound_page_title),
-                        new SoundPickerFragment());
-                break;
-        }
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/VibrationPickerFragment.java b/packages/SoundPicker2/src/com/android/soundpicker/VibrationPickerFragment.java
deleted file mode 100644
index 7412c19..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/VibrationPickerFragment.java
+++ /dev/null
@@ -1,52 +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 com.android.soundpicker;
-
-import android.os.Bundle;
-import android.view.View;
-
-import androidx.lifecycle.ViewModelProvider;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A fragment that displays a picker used to select vibration or silent (no vibration).
- */
-public class VibrationPickerFragment extends BasePickerFragment {
-
-    @Override
-    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
-        mRingtonePickerViewModel = new ViewModelProvider(requireActivity()).get(
-                RingtonePickerViewModel.class);
-        super.onViewCreated(view, savedInstanceState);
-    }
-
-    @Override
-    protected RingtoneListHandler getRingtoneListHandler() {
-        return mRingtonePickerViewModel.getVibrationListHandler();
-    }
-
-    @Override
-    protected void addRingtoneAsync() {
-        // no-op
-    }
-
-    @Override
-    protected void addNewRingtoneItem() {
-        // no-op
-    }
-}
diff --git a/packages/SoundPicker2/src/com/android/soundpicker/ViewPagerAdapter.java b/packages/SoundPicker2/src/com/android/soundpicker/ViewPagerAdapter.java
deleted file mode 100644
index 179068e..0000000
--- a/packages/SoundPicker2/src/com/android/soundpicker/ViewPagerAdapter.java
+++ /dev/null
@@ -1,70 +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 com.android.soundpicker;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * An adapter used to populate pages inside a ViewPager.
- */
-public class ViewPagerAdapter extends FragmentStateAdapter {
-
-    private final List<Fragment> mFragments = new ArrayList<>();
-    private final List<String> mTitles = new ArrayList<>();
-
-    public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
-        super(fragmentActivity);
-    }
-
-    /**
-     * Adds a fragment and page title to the adapter.
-     * @param title the title of the page in the ViewPager.
-     * @param fragment the fragment that will be inflated on this page.
-     */
-    public void addFragment(String title, Fragment fragment) {
-        mTitles.add(title);
-        mFragments.add(fragment);
-    }
-
-    /**
-     * Returns the title of the requested page.
-     * @param position the position of the page in the Viewpager.
-     * @return The title of the requested page.
-     */
-    public String getTitle(int position) {
-        return mTitles.get(position);
-    }
-
-    @NonNull
-    @Override
-    public Fragment createFragment(int position) {
-        return Objects.requireNonNull(mFragments.get(position),
-                "Could not find a fragment using position: " + position);
-    }
-
-    @Override
-    public int getItemCount() {
-        return mFragments.size();
-    }
-}
diff --git a/packages/SoundPicker2/tests/Android.bp b/packages/SoundPicker2/tests/Android.bp
deleted file mode 100644
index d88d442..0000000
--- a/packages/SoundPicker2/tests/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 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 {
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
-    name: "SoundPicker2Tests",
-    certificate: "platform",
-    libs: [
-        "android.test.runner",
-        "android.test.base",
-    ],
-    static_libs: [
-        "androidx.test.core",
-        "androidx.test.rules",
-        "androidx.test.ext.junit",
-        "androidx.test.ext.truth",
-        "mockito-target-minus-junit4",
-        "guava-android-testlib",
-        "SoundPicker2Lib",
-    ],
-    srcs: [
-        "src/**/*.java",
-    ],
-}
diff --git a/packages/SoundPicker2/tests/AndroidManifest.xml b/packages/SoundPicker2/tests/AndroidManifest.xml
deleted file mode 100644
index 295aeb1..0000000
--- a/packages/SoundPicker2/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.soundpicker.tests">
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.soundpicker.tests"
-        android:label="Sound picker tests">
-    </instrumentation>
-</manifest>
diff --git a/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtoneListHandlerTest.java b/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtoneListHandlerTest.java
deleted file mode 100644
index 80e71e200..0000000
--- a/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtoneListHandlerTest.java
+++ /dev/null
@@ -1,167 +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 com.android.soundpicker;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.database.Cursor;
-import android.media.RingtoneManager;
-import android.net.Uri;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class RingtoneListHandlerTest {
-
-    private static final Uri DEFAULT_URI = Uri.parse("media://custom/ringtone/default_uri");
-    private static final Uri RINGTONE_URI = Uri.parse("media://custom/ringtone/uri");
-    private static final int SILENT_RINGTONE_POSITION = 0;
-    private static final int DEFAULT_RINGTONE_POSITION = 1;
-    private static final int RINGTONE_POSITION = 2;
-
-    @Mock
-    private RingtoneManager mMockRingtoneManager;
-    @Mock
-    private Cursor mMockCursor;
-
-    private RingtoneListHandler mRingtoneListHandler;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        RingtoneListHandler.Config mRingtoneListConfig = createRingtoneListConfig();
-
-        mRingtoneListHandler = new RingtoneListHandler();
-
-        // Add silent and default options to the list.
-        mRingtoneListHandler.addSilentItem();
-        mRingtoneListHandler.addDefaultItem();
-
-        mRingtoneListHandler.init(mRingtoneListConfig, mMockRingtoneManager, mMockCursor);
-    }
-
-    @Test
-    public void testGetRingtoneCursor_returnsTheCorrectRingtoneCursor() {
-        assertThat(mRingtoneListHandler.getRingtoneCursor()).isEqualTo(mMockCursor);
-    }
-
-    @Test
-    public void testGetRingtoneUri_returnsTheCorrectRingtoneUri() {
-        Uri expectedUri = RINGTONE_URI;
-        when(mMockRingtoneManager.getRingtoneUri(eq(0))).thenReturn(expectedUri);
-
-        // Request 3rd item from list.
-        Uri actualUri = mRingtoneListHandler.getRingtoneUri(RINGTONE_POSITION);
-        assertThat(actualUri).isEqualTo(expectedUri);
-    }
-
-    @Test
-    public void testGetRingtoneUri_withSelectedItemUnknown_returnsTheCorrectRingtoneUri() {
-        Uri uri = mRingtoneListHandler.getRingtoneUri(RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-        assertThat(uri).isEqualTo(RingtoneListHandler.SILENT_URI);
-    }
-
-    @Test
-    public void testGetRingtoneUri_withSelectedItemDefaultPosition_returnsTheCorrectRingtoneUri() {
-        Uri actualUri = mRingtoneListHandler.getRingtoneUri(DEFAULT_RINGTONE_POSITION);
-        assertThat(actualUri).isEqualTo(DEFAULT_URI);
-    }
-
-    @Test
-    public void testGetRingtoneUri_withSelectedItemSilentPosition_returnsTheCorrectRingtoneUri() {
-        Uri uri = mRingtoneListHandler.getRingtoneUri(SILENT_RINGTONE_POSITION);
-        assertThat(uri).isEqualTo(RingtoneListHandler.SILENT_URI);
-    }
-
-    @Test
-    public void testGetCurrentlySelectedRingtoneUri_returnsTheCorrectRingtoneUri() {
-        mRingtoneListHandler.setSelectedItemPosition(RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-        Uri actualUri = mRingtoneListHandler.getSelectedRingtoneUri();
-        assertThat(actualUri).isEqualTo(RingtoneListHandler.SILENT_URI);
-
-        mRingtoneListHandler.setSelectedItemPosition(DEFAULT_RINGTONE_POSITION);
-        actualUri = mRingtoneListHandler.getSelectedRingtoneUri();
-        assertThat(actualUri).isEqualTo(DEFAULT_URI);
-
-        mRingtoneListHandler.setSelectedItemPosition(SILENT_RINGTONE_POSITION);
-        actualUri = mRingtoneListHandler.getSelectedRingtoneUri();
-        assertThat(actualUri).isEqualTo(RingtoneListHandler.SILENT_URI);
-
-        when(mMockRingtoneManager.getRingtoneUri(eq(0))).thenReturn(RINGTONE_URI);
-        mRingtoneListHandler.setSelectedItemPosition(RINGTONE_POSITION);
-        actualUri = mRingtoneListHandler.getSelectedRingtoneUri();
-        assertThat(actualUri).isEqualTo(RINGTONE_URI);
-    }
-
-    @Test
-    public void testGetRingtonePosition_returnsTheCorrectRingtonePosition() {
-        when(mMockRingtoneManager.getRingtonePosition(RINGTONE_URI)).thenReturn(0);
-
-        int actualPosition = mRingtoneListHandler.getRingtonePosition(RINGTONE_URI);
-
-        assertThat(actualPosition).isEqualTo(RINGTONE_POSITION);
-
-    }
-
-    @Test
-    public void testFixedItems_onlyAddsItemsOnceAndInOrder() {
-        // Clear fixed items before testing the add methods.
-        mRingtoneListHandler.resetFixedItems();
-
-        assertThat(mRingtoneListHandler.getSilentItemPosition()).isEqualTo(
-                RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-        assertThat(mRingtoneListHandler.getDefaultItemPosition()).isEqualTo(
-                RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-
-        mRingtoneListHandler.addSilentItem();
-        mRingtoneListHandler.addDefaultItem();
-        mRingtoneListHandler.addSilentItem();
-        mRingtoneListHandler.addDefaultItem();
-
-        assertThat(mRingtoneListHandler.getSilentItemPosition()).isEqualTo(
-                SILENT_RINGTONE_POSITION);
-        assertThat(mRingtoneListHandler.getDefaultItemPosition()).isEqualTo(
-                DEFAULT_RINGTONE_POSITION);
-    }
-
-    @Test
-    public void testResetFixedItems_resetsSilentAndDefaultItemPositions() {
-        assertThat(mRingtoneListHandler.getSilentItemPosition()).isEqualTo(
-                SILENT_RINGTONE_POSITION);
-        assertThat(mRingtoneListHandler.getDefaultItemPosition()).isEqualTo(
-                DEFAULT_RINGTONE_POSITION);
-
-        mRingtoneListHandler.resetFixedItems();
-
-        assertThat(mRingtoneListHandler.getSilentItemPosition()).isEqualTo(
-                RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-        assertThat(mRingtoneListHandler.getDefaultItemPosition()).isEqualTo(
-                RingtoneListHandler.ITEM_POSITION_UNKNOWN);
-    }
-
-    private RingtoneListHandler.Config createRingtoneListConfig() {
-        return new RingtoneListHandler.Config(/* hasDefaultItem= */ true,
-                /* uriForDefaultItem= */ DEFAULT_URI, /* hasSilentItem= */ true,
-                /* existingUri= */ DEFAULT_URI);
-    }
-}
diff --git a/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtonePickerViewModelTest.java b/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtonePickerViewModelTest.java
deleted file mode 100644
index cde6c76..0000000
--- a/packages/SoundPicker2/tests/src/com/android/soundpicker/RingtonePickerViewModelTest.java
+++ /dev/null
@@ -1,534 +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 com.android.soundpicker;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.database.Cursor;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.provider.Settings;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.testing.TestingExecutors;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-
-@RunWith(AndroidJUnit4.class)
-public class RingtonePickerViewModelTest {
-
-    private static final Uri DEFAULT_URI = Uri.parse("media://custom/ringtone/default_uri");
-    private static final Uri RINGTONE_URI = Uri.parse("media://custom/ringtone/uri");
-    private static final int RINGTONE_TYPE_UNKNOWN = -1;
-    private static final int DEFAULT_RINGTONE_POSITION = 1;
-
-    @Mock
-    private RingtoneManagerFactory mMockRingtoneManagerFactory;
-    @Mock
-    private RingtoneFactory mMockRingtoneFactory;
-    @Mock
-    private RingtoneManager mMockRingtoneManager;
-    @Mock
-    private ListeningExecutorServiceFactory mMockListeningExecutorServiceFactory;
-    @Mock
-    private Cursor mMockCursor;
-
-    private RingtoneListHandler mSoundListHandler;
-    private RingtoneListHandler mVibrationListHandler;
-    private ExecutorService mMainThreadExecutor;
-    private ListeningExecutorService mBackgroundThreadExecutor;
-    private Ringtone mMockDefaultRingtone;
-    private Ringtone mMockRingtone;
-    private RingtonePickerViewModel mViewModel;
-    private RingtoneListHandler.Config mSoundListConfig;
-    private RingtoneListHandler.Config mVibrationListConfig;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        mSoundListHandler = new RingtoneListHandler();
-        mVibrationListHandler = new RingtoneListHandler();
-        mSoundListConfig = createRingtoneListConfig();
-        mVibrationListConfig = createRingtoneListConfig();
-        mMockDefaultRingtone = createMockRingtone();
-        mMockRingtone = createMockRingtone();
-        when(mMockRingtoneManagerFactory.create()).thenReturn(mMockRingtoneManager);
-        when(mMockRingtoneFactory.create(DEFAULT_URI,
-                AudioAttributes.FLAG_AUDIBILITY_ENFORCED)).thenReturn(mMockDefaultRingtone);
-        when(mMockRingtoneManager.getRingtoneUri(anyInt())).thenReturn(RINGTONE_URI);
-        when(mMockRingtoneManager.getCursor()).thenReturn(mMockCursor);
-        mMainThreadExecutor = TestingExecutors.sameThreadScheduledExecutor();
-        mBackgroundThreadExecutor = TestingExecutors.sameThreadScheduledExecutor();
-        when(mMockListeningExecutorServiceFactory.createSingleThreadExecutor()).thenReturn(
-                mBackgroundThreadExecutor);
-
-        mViewModel = new RingtonePickerViewModel(mMockRingtoneManagerFactory, mMockRingtoneFactory,
-                mMockListeningExecutorServiceFactory, mSoundListHandler,
-                mVibrationListHandler);
-
-        // Add silent and default options to the sound list.
-        mSoundListHandler.addSilentItem();
-        mSoundListHandler.addDefaultItem();
-
-        // Add silent and default options to the vibration list.
-        mVibrationListHandler.addSilentItem();
-        mVibrationListHandler.addDefaultItem();
-
-        mSoundListHandler.setSelectedItemPosition(DEFAULT_RINGTONE_POSITION);
-        mVibrationListHandler.setSelectedItemPosition(DEFAULT_RINGTONE_POSITION);
-    }
-
-    @After
-    public void teardown() {
-        if (mMainThreadExecutor != null && !mMainThreadExecutor.isShutdown()) {
-            mMainThreadExecutor.shutdown();
-        }
-        if (mBackgroundThreadExecutor != null && !mBackgroundThreadExecutor.isShutdown()) {
-            mBackgroundThreadExecutor.shutdown();
-        }
-    }
-
-    @Test
-    public void testInitRingtoneManager_whenTypeIsUnknown_createManagerButDoNotSetType() {
-        mViewModel.init(createPickerConfig(RINGTONE_TYPE_UNKNOWN), mSoundListConfig,
-                mVibrationListConfig);
-
-        verify(mMockRingtoneManagerFactory).create();
-        verify(mMockRingtoneManager, never()).setType(anyInt());
-        assertNotNull(mViewModel.getSoundListHandler().getRingtoneListConfig());
-        assertNotNull(mViewModel.getVibrationListHandler().getRingtoneListConfig());
-    }
-
-    @Test
-    public void testInitRingtoneManager_whenTypeIsNotUnknown_createManagerAndSetType() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_NOTIFICATION), mSoundListConfig,
-                mVibrationListConfig);
-
-        verify(mMockRingtoneManagerFactory).create();
-        verify(mMockRingtoneManager).setType(RingtoneManager.TYPE_NOTIFICATION);
-        assertNotNull(mViewModel.getSoundListHandler().getRingtoneListConfig());
-        assertNotNull(mViewModel.getVibrationListHandler().getRingtoneListConfig());
-    }
-
-    @Test
-    public void testInitRingtoneManager_bothListConfigsAreNull_onlyRecreateRingtoneManager() {
-        mViewModel.init(
-                createPickerConfig(RingtoneManager.TYPE_NOTIFICATION),
-                /* soundListConfig= */ null, /* vibrationListConfig= */ null);
-
-        verify(mMockRingtoneManagerFactory).create();
-        verify(mMockRingtoneManager).setType(RingtoneManager.TYPE_NOTIFICATION);
-        assertNull(mViewModel.getSoundListHandler().getRingtoneListConfig());
-        assertNull(mViewModel.getVibrationListHandler().getRingtoneListConfig());
-    }
-
-    @Test
-    public void testReinitialize_bothListConfigsInitialized_recreateManagerAndReinitHandlers() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_NOTIFICATION), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.reinit();
-
-        verify(mMockRingtoneManagerFactory, times(2)).create();
-        verify(mMockRingtoneManager, times(2)).setType(RingtoneManager.TYPE_NOTIFICATION);
-        assertNotNull(mViewModel.getSoundListHandler().getRingtoneListConfig());
-        assertNotNull(mViewModel.getVibrationListHandler().getRingtoneListConfig());
-    }
-
-    @Test
-    public void testReinitialize_bothListConfigsAlreadyNull_onlyRecreateRingtoneManager() {
-        mViewModel.init(
-                createPickerConfig(RingtoneManager.TYPE_NOTIFICATION),
-                /* soundListConfig= */ null, /* vibrationListConfig= */ null);
-        mViewModel.reinit();
-
-        verify(mMockRingtoneManagerFactory, times(2)).create();
-        verify(mMockRingtoneManager, times(2)).setType(RingtoneManager.TYPE_NOTIFICATION);
-        assertNull(mViewModel.getSoundListHandler().getRingtoneListConfig());
-        assertNull(mViewModel.getVibrationListHandler().getRingtoneListConfig());
-    }
-
-    @Test
-    public void testGetStreamType_returnsTheCorrectStreamType() {
-        when(mMockRingtoneManager.inferStreamType()).thenReturn(AudioManager.STREAM_ALARM);
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        assertEquals(mViewModel.getRingtoneStreamType(), AudioManager.STREAM_ALARM);
-    }
-
-    @Test
-    public void testOnPause_withChangingConfigurationTrue_doNotStopPlayingRingtone() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        mViewModel.onPause(/* isChangingConfigurations= */ true);
-        verify(mMockDefaultRingtone, never()).stop();
-    }
-
-    @Test
-    public void testOnPause_withChangingConfigurationFalse_stopPlayingRingtone() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        mViewModel.onPause(/* isChangingConfigurations= */ false);
-        verify(mMockDefaultRingtone).stop();
-    }
-
-    @Test
-    public void testOnViewModelRecreated_previousRingtoneCanStillBeStopped() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        Ringtone mockRingtone1 = createMockRingtone();
-        Ringtone mockRingtone2 = createMockRingtone();
-
-        when(mMockRingtoneFactory.create(any(), anyInt())).thenReturn(mockRingtone1, mockRingtone2);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mockRingtone1);
-        // Fake a scenario where the activity is destroyed and recreated due to a config change.
-        // This will result in a new view model getting created.
-        mViewModel.onStop(/* isChangingConfigurations= */ true);
-        verify(mockRingtone1, never()).stop();
-        mViewModel = new RingtonePickerViewModel(mMockRingtoneManagerFactory, mMockRingtoneFactory,
-                mMockListeningExecutorServiceFactory, mSoundListHandler,
-                mVibrationListHandler);
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mockRingtone2);
-        verify(mockRingtone1).stop();
-        verify(mockRingtone2, never()).stop();
-    }
-
-    @Test
-    public void testOnStop_withChangingConfigurationTrueAndDefaultRingtonePlaying_saveRingtone() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        mViewModel.onStop(/* isChangingConfigurations= */ true);
-        assertEquals(RingtonePickerViewModel.sPlayingRingtone, mMockDefaultRingtone);
-    }
-
-    @Test
-    public void testOnStop_withChangingConfigurationTrueAndCurrentRingtonePlaying_saveRingtone() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        mViewModel.onStop(/* isChangingConfigurations= */ true);
-        assertEquals(RingtonePickerViewModel.sPlayingRingtone, mMockDefaultRingtone);
-    }
-
-    @Test
-    public void testOnStop_withChangingConfigurationTrueAndNoPlayingRingtone_saveNothing() {
-        mViewModel.onStop(/* isChangingConfigurations= */ true);
-        assertNull(RingtonePickerViewModel.sPlayingRingtone);
-    }
-
-    @Test
-    public void testOnStop_withChangingConfigurationFalse_stopPlayingRingtone() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        mViewModel.onStop(/* isChangingConfigurations= */ false);
-        verify(mMockDefaultRingtone).stop();
-    }
-
-    @Test
-    public void testGetCurrentlySelectedRingtoneUri_returnsTheCorrectRingtoneUri() {
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-
-        assertEquals(DEFAULT_URI, mViewModel.getSelectedRingtoneUri());
-    }
-
-    @Test
-    public void testPlayRingtone_playTheCorrectRingtone() {
-        mSoundListHandler.setSelectedItemPosition(DEFAULT_RINGTONE_POSITION);
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-    }
-
-    @Test
-    public void testPlayRingtone_stopsPreviouslyRunningRingtone() {
-        // Start playing the first ringtone
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockDefaultRingtone);
-        // Start playing the second ringtone
-        when(mMockRingtoneFactory.create(DEFAULT_URI,
-                AudioAttributes.FLAG_AUDIBILITY_ENFORCED)).thenReturn(mMockRingtone);
-        mViewModel.playRingtone();
-        verifyRingtonePlayCalledAndMockPlayingState(mMockRingtone);
-
-        verify(mMockDefaultRingtone).stop();
-    }
-
-    @Test
-    public void testDefaultItemUri_withNotificationIntent_returnDefaultNotificationUri() {
-        Uri uri = RingtonePickerViewModel.getDefaultItemUriByType(
-                RingtoneManager.TYPE_NOTIFICATION);
-        assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, uri);
-    }
-
-    @Test
-    public void testDefaultItemUri_withAlarmIntent_returnDefaultAlarmUri() {
-        Uri uri = RingtonePickerViewModel.getDefaultItemUriByType(RingtoneManager.TYPE_ALARM);
-        assertEquals(Settings.System.DEFAULT_ALARM_ALERT_URI, uri);
-    }
-
-    @Test
-    public void testDefaultItemUri_withRingtoneIntent_returnDefaultRingtoneUri() {
-        Uri uri = RingtonePickerViewModel.getDefaultItemUriByType(RingtoneManager.TYPE_RINGTONE);
-        assertEquals(Settings.System.DEFAULT_RINGTONE_URI, uri);
-    }
-
-    @Test
-    public void testDefaultItemUri_withInvalidRingtoneType_returnDefaultRingtoneUri() {
-        Uri uri = RingtonePickerViewModel.getDefaultItemUriByType(-1);
-        assertEquals(Settings.System.DEFAULT_RINGTONE_URI, uri);
-    }
-
-    @Test
-    public void testTitle_withNotificationRingtoneType_returnRingtoneNotificationTitle() {
-        int title = RingtonePickerViewModel.getTitleByType(RingtoneManager.TYPE_NOTIFICATION);
-        assertEquals(com.android.internal.R.string.ringtone_picker_title_notification, title);
-    }
-
-    @Test
-    public void testTitle_withAlarmRingtoneType_returnRingtoneAlarmTitle() {
-        int title = RingtonePickerViewModel.getTitleByType(RingtoneManager.TYPE_ALARM);
-        assertEquals(com.android.internal.R.string.ringtone_picker_title_alarm, title);
-    }
-
-    @Test
-    public void testTitle_withInvalidRingtoneType_returnDefaultRingtoneTitle() {
-        int title = RingtonePickerViewModel.getTitleByType(/*ringtoneType= */ -1);
-        assertEquals(com.android.internal.R.string.ringtone_picker_title, title);
-    }
-
-    @Test
-    public void testAddNewItemText_withAlarmType_returnAlarmAddItemText() {
-        int addNewItemTextResId = RingtonePickerViewModel.getAddNewItemTextByType(
-                RingtoneManager.TYPE_ALARM);
-        assertEquals(R.string.add_alarm_text, addNewItemTextResId);
-    }
-
-    @Test
-    public void testAddNewItemText_withNotificationType_returnNotificationAddItemText() {
-        int addNewItemTextResId = RingtonePickerViewModel.getAddNewItemTextByType(
-                RingtoneManager.TYPE_NOTIFICATION);
-        assertEquals(R.string.add_notification_text, addNewItemTextResId);
-    }
-
-    @Test
-    public void testAddNewItemText_withRingtoneType_returnRingtoneAddItemText() {
-        int addNewItemTextResId = RingtonePickerViewModel.getAddNewItemTextByType(
-                RingtoneManager.TYPE_RINGTONE);
-        assertEquals(R.string.add_ringtone_text, addNewItemTextResId);
-    }
-
-    @Test
-    public void testAddNewItemText_withInvalidType_returnRingtoneAddItemText() {
-        int addNewItemTextResId = RingtonePickerViewModel.getAddNewItemTextByType(-1);
-        assertEquals(R.string.add_ringtone_text, addNewItemTextResId);
-    }
-
-    @Test
-    public void testDefaultItemText_withNotificationType_returnNotificationDefaultItemText() {
-        int defaultRingtoneItemText = RingtonePickerViewModel.getDefaultRingtoneItemTextByType(
-                RingtoneManager.TYPE_NOTIFICATION);
-        assertEquals(R.string.notification_sound_default, defaultRingtoneItemText);
-    }
-
-    @Test
-    public void testDefaultItemText_withAlarmType_returnAlarmDefaultItemText() {
-        int defaultRingtoneItemText = RingtonePickerViewModel.getDefaultRingtoneItemTextByType(
-                RingtoneManager.TYPE_NOTIFICATION);
-        assertEquals(R.string.notification_sound_default, defaultRingtoneItemText);
-    }
-
-    @Test
-    public void testDefaultItemText_withRingtoneType_returnRingtoneDefaultItemText() {
-        int defaultRingtoneItemText = RingtonePickerViewModel.getDefaultRingtoneItemTextByType(
-                RingtoneManager.TYPE_RINGTONE);
-        assertEquals(R.string.ringtone_default, defaultRingtoneItemText);
-    }
-
-    @Test
-    public void testDefaultItemText_withInvalidType_returnRingtoneDefaultItemText() {
-        int defaultRingtoneItemText = RingtonePickerViewModel.getDefaultRingtoneItemTextByType(-1);
-        assertEquals(R.string.ringtone_default, defaultRingtoneItemText);
-    }
-
-    @Test
-    public void testCancelPendingAsyncTasks_correctlyCancelsPendingTasks()
-            throws IOException {
-        FutureCallback<Uri> mockCallback = mock(FutureCallback.class);
-
-        when(mMockListeningExecutorServiceFactory.createSingleThreadExecutor()).thenReturn(
-                TestingExecutors.noOpScheduledExecutor());
-
-        mViewModel = new RingtonePickerViewModel(mMockRingtoneManagerFactory, mMockRingtoneFactory,
-                mMockListeningExecutorServiceFactory, mSoundListHandler,
-                mVibrationListHandler);
-        mViewModel.addSoundRingtoneAsync(DEFAULT_URI, RingtoneManager.TYPE_NOTIFICATION,
-                mockCallback, mMainThreadExecutor);
-        verify(mockCallback, never()).onFailure(any());
-        // Calling cancelPendingAsyncTasks should cancel the pending task. Cancelling an async
-        // task invokes the onFailure method in the callable.
-        mViewModel.cancelPendingAsyncTasks();
-        verify(mockCallback).onFailure(any());
-        verify(mockCallback, never()).onSuccess(any());
-
-    }
-
-    @Test
-    public void testAddRingtoneAsync_cancelPreviousTaskBeforeStartingNewOne()
-            throws IOException {
-        FutureCallback<Uri> mockCallback1 = mock(FutureCallback.class);
-        FutureCallback<Uri> mockCallback2 = mock(FutureCallback.class);
-
-        when(mMockListeningExecutorServiceFactory.createSingleThreadExecutor()).thenReturn(
-                TestingExecutors.noOpScheduledExecutor());
-
-        mViewModel = new RingtonePickerViewModel(mMockRingtoneManagerFactory, mMockRingtoneFactory,
-                mMockListeningExecutorServiceFactory, mSoundListHandler,
-                mVibrationListHandler);
-        mViewModel.addSoundRingtoneAsync(DEFAULT_URI, RingtoneManager.TYPE_NOTIFICATION,
-                mockCallback1, mMainThreadExecutor);
-        verify(mockCallback1, never()).onFailure(any());
-        // We call addRingtoneAsync again to cancel the previous task and start a new one.
-        // Cancelling an async task invokes the onFailure method in the callable.
-        mViewModel.addSoundRingtoneAsync(DEFAULT_URI, RingtoneManager.TYPE_NOTIFICATION,
-                mockCallback2, mMainThreadExecutor);
-        verify(mockCallback1).onFailure(any());
-        verify(mockCallback1, never()).onSuccess(any());
-        verifyNoMoreInteractions(mockCallback2);
-    }
-
-    @Test
-    public void testAddRingtoneAsync_whenAddRingtoneIsSuccessful_successCallbackIsInvoked()
-            throws IOException {
-        Uri expectedUri = DEFAULT_URI;
-        FutureCallback<Uri> mockCallback = mock(FutureCallback.class);
-
-        when(mMockRingtoneManager.addCustomExternalRingtone(DEFAULT_URI,
-                RingtoneManager.TYPE_NOTIFICATION)).thenReturn(expectedUri);
-
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-
-        mViewModel.addSoundRingtoneAsync(DEFAULT_URI, RingtoneManager.TYPE_NOTIFICATION,
-                mockCallback, mMainThreadExecutor);
-
-        verify(mockCallback).onSuccess(expectedUri);
-        verify(mockCallback, never()).onFailure(any());
-    }
-
-    @Test
-    public void testAddRingtoneAsync_whenAddRingtoneFailed_failureCallbackIsInvoked()
-            throws IOException {
-        FutureCallback<Uri> mockCallback = mock(FutureCallback.class);
-
-        when(mMockRingtoneManager.addCustomExternalRingtone(any(), anyInt())).thenThrow(
-                IOException.class);
-
-        mViewModel.init(createPickerConfig(RingtoneManager.TYPE_RINGTONE), mSoundListConfig,
-                mVibrationListConfig);
-
-        mViewModel.addSoundRingtoneAsync(DEFAULT_URI, RingtoneManager.TYPE_NOTIFICATION,
-                mockCallback, mMainThreadExecutor);
-
-        verify(mockCallback).onFailure(any(IOException.class));
-        verify(mockCallback, never()).onSuccess(any());
-    }
-
-    private Ringtone createMockRingtone() {
-        Ringtone mockRingtone = mock(Ringtone.class);
-        when(mockRingtone.getAudioAttributes()).thenReturn(
-                audioAttributes(AudioAttributes.USAGE_NOTIFICATION_RINGTONE, 0));
-
-        return mockRingtone;
-    }
-
-    private void verifyRingtonePlayCalledAndMockPlayingState(Ringtone ringtone) {
-        verify(ringtone).play();
-        when(ringtone.isPlaying()).thenReturn(true);
-    }
-
-    private static AudioAttributes audioAttributes(int audioUsage, int flags) {
-        return new AudioAttributes.Builder()
-                .setUsage(audioUsage)
-                .setFlags(flags)
-                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                .build();
-    }
-
-    private RingtonePickerViewModel.Config createPickerConfig(int ringtoneType,
-            int audioAttributes) {
-        return new RingtonePickerViewModel.Config("Phone ringtone", /* userId= */ 1,
-                ringtoneType, /* showOkCancelButtons= */ true,
-                audioAttributes, RingtonePickerViewModel.PickerType.RINGTONE_PICKER);
-    }
-
-    private RingtonePickerViewModel.Config createPickerConfig(int ringtoneType) {
-        return new RingtonePickerViewModel.Config("Phone ringtone", /* userId= */ 1,
-                ringtoneType, /* showOkCancelButtons= */ true,
-                AudioAttributes.FLAG_AUDIBILITY_ENFORCED,
-                RingtonePickerViewModel.PickerType.RINGTONE_PICKER);
-    }
-
-    private RingtoneListHandler.Config createRingtoneListConfig() {
-        return new RingtoneListHandler.Config(/* hasDefaultItem= */ true,
-                /* uriForDefaultItem= */ DEFAULT_URI, /* hasSilentItem= */ true,
-                /* existingUri= */ Uri.parse(""));
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 7a48836..3ab0420 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.media;
 
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -37,8 +34,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.vibrator.Flags;
 import android.provider.MediaStore;
 import android.util.Log;
 
@@ -58,7 +53,7 @@
 @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
@@ -91,11 +86,20 @@
      */
     private class Client implements IBinder.DeathRecipient {
         private final IBinder mToken;
-        private Ringtone mRingtone;
+        private final Ringtone mRingtone;
 
-        Client(@NonNull IBinder token, @NonNull Ringtone ringtone) {
-            mToken = requireNonNull(token);
-            mRingtone = requireNonNull(ringtone);
+        public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
+            this(token, uri, user, aa, null);
+        }
+
+        Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa,
+                @Nullable VolumeShaper.Configuration volumeShaperConfig) {
+            mToken = token;
+
+            mRingtone = new Ringtone(getContextForUser(user), false);
+            mRingtone.setAudioAttributesField(aa);
+            mRingtone.setUri(uri, volumeShaperConfig);
+            mRingtone.createLocalMediaPlayer();
         }
 
         @Override
@@ -112,48 +116,24 @@
         @Override
         public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
                 throws RemoteException {
-            if (Flags.hapticsCustomizationRingtoneV2Enabled()) {
-                playRemoteRingtone(token, uri, aa, true, Ringtone.MEDIA_SOUND,
-                        null, volume, looping, /* hapticGenerator= */ false,
-                        null);
-            } else {
-                playWithVolumeShaping(token, uri, aa, volume, looping, null);
-            }
+            playWithVolumeShaping(token, uri, aa, volume, looping, null);
         }
-
         @Override
-        public void playWithVolumeShaping(
-                IBinder token, Uri uri, AudioAttributes aa, float volume,
+        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="
+                Log.d(TAG, "play(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();
+                if (client == null) {
+                    final UserHandle user = Binder.getCallingUserHandle();
+                    client = new Client(token, uri, user, aa, volumeShaperConfig);
+                    token.linkToDeath(client, 0);
+                    mClients.put(token, client);
                 }
             }
             client.mRingtone.setLooping(looping);
@@ -162,54 +142,6 @@
         }
 
         @Override
-        public void playRemoteRingtone(IBinder token, Uri uri, AudioAttributes aa,
-                boolean useExactAudioAttributes,
-                @Ringtone.RingtoneMedia int enabledMedia, @Nullable VibrationEffect vibrationEffect,
-                float volume,
-                boolean looping, boolean isHapticGeneratorEnabled,
-                @Nullable VolumeShaper.Configuration volumeShaperConfig)
-                throws RemoteException {
-            if (LOGD) {
-                Log.d(TAG, "playRemoteRingtone(token=" + token + ", uri=" + uri + ", uid="
-                        + Binder.getCallingUid() + ")");
-            }
-
-            // 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.
-            Client client;
-            synchronized (mClients) {
-                client = mClients.get(token);
-            }
-            if (client == null) {
-                final UserHandle user = Binder.getCallingUserHandle();
-                Ringtone ringtone = new Ringtone.Builder(getContextForUser(user), enabledMedia, aa)
-                        .setLocalOnly()
-                        .setUri(uri)
-                        .setLooping(looping)
-                        .setInitialSoundVolume(volume)
-                        .setUseExactAudioAttributes(useExactAudioAttributes)
-                        .setEnableHapticGenerator(isHapticGeneratorEnabled)
-                        .setVibrationEffect(vibrationEffect)
-                        .setVolumeShaperConfig(volumeShaperConfig)
-                        .build();
-                if (ringtone == null) {
-                    return;
-                }
-                synchronized (mClients) {
-                    client = mClients.get(token);
-                    if (client == null) {
-                        client = new Client(token, ringtone);
-                        token.linkToDeath(client, 0);
-                        mClients.put(token, client);
-                    }
-                }
-            }
-            // Ensure the client is initialized outside the all-clients lock, as it can be slow.
-            client.mRingtone.play();
-        }
-
-        @Override
         public void stop(IBinder token) {
             if (LOGD) Log.d(TAG, "stop(token=" + token + ")");
             Client client;
@@ -235,10 +167,10 @@
                 return false;
             }
         }
+
         @Override
         public void setPlaybackProperties(IBinder token, float volume, boolean looping,
-                                          boolean hapticGeneratorEnabled) {
-            // RingtoneV1-exclusive path.
+                boolean hapticGeneratorEnabled) {
             Client client;
             synchronized (mClients) {
                 client = mClients.get(token);
@@ -252,39 +184,6 @@
         }
 
         @Override
-        public void setHapticGeneratorEnabled(IBinder token, boolean hapticGeneratorEnabled) {
-            Client client;
-            synchronized (mClients) {
-                client = mClients.get(token);
-            }
-            if (client != null) {
-                client.mRingtone.setHapticGeneratorEnabled(hapticGeneratorEnabled);
-            }
-        }
-
-        @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
         public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa,
                 float volume) {
             if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index 9554e63..fb527c1 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -20,8 +20,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
-import android.media.AudioAttributes;
+import android.media.AudioManager;
 import android.media.Ringtone;
+import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
@@ -305,16 +306,11 @@
                     if (soundPath != null) {
                         final Uri soundUri = Uri.parse("file://" + soundPath);
                         if (soundUri != null) {
-                            AudioAttributes audioAttributes = new AudioAttributes.Builder()
-                                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                                    .build();
-                            final Ringtone sfx = new Ringtone.Builder(getContext(),
-                                    Ringtone.MEDIA_SOUND, audioAttributes)
-                                    .setUri(soundUri)
-                                    .setPreferBuiltinDevice()
-                                    .build();
+                            final Ringtone sfx = RingtoneManager.getRingtone(
+                                    getContext(), soundUri);
                             if (sfx != null) {
+                                sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                                sfx.preferBuiltinDevice(true);
                                 sfx.play();
                             }
                         }