Merge "Reuse ringtone across multiple ringer operations"

This commit is contained in:
TreeHugger Robot
2022-11-09 19:26:37 +00:00
committed by Android (Google) Code Review
2 changed files with 71 additions and 38 deletions

View File

@@ -158,13 +158,15 @@ public class Ringtone {
/**
* 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 void createLocalMediaPlayer() {
public boolean createLocalMediaPlayer() {
Trace.beginSection("createLocalMediaPlayer");
if (mUri == null) {
Log.e(TAG, "Could not create media player as no URI was provided.");
return;
return mAllowRemote && mRemotePlayer != null;
}
destroyLocalPlayer();
// try opening uri locally before delegating to remote player
@@ -195,6 +197,30 @@ public class Ringtone {
}
}
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;
}
/**
@@ -423,7 +449,6 @@ public class Ringtone {
*/
public void setUri(Uri uri, @Nullable VolumeShaper.Configuration volumeShaperConfig) {
mVolumeShaperConfig = volumeShaperConfig;
mUri = uri;
if (mUri == null) {
destroyLocalPlayer();
@@ -443,10 +468,11 @@ public class Ringtone {
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).
boolean isHapticOnly = AudioManager.hasHapticChannels(mContext, mUri)
&& !mAudioAttributes.areHapticChannelsMuted() && mVolume == 0;
if (isHapticOnly || mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
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)) {

View File

@@ -720,11 +720,14 @@ public class RingtoneManager {
@Nullable VolumeShaper.Configuration volumeShaperConfig,
AudioAttributes audioAttributes) {
// Don't set the stream type
Ringtone ringtone =
getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false);
Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */,
volumeShaperConfig, false);
if (ringtone != null) {
ringtone.setAudioAttributesField(audioAttributes);
ringtone.createLocalMediaPlayer();
if (!ringtone.createLocalMediaPlayer()) {
Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
return null;
}
}
return ringtone;
}
@@ -750,19 +753,6 @@ public class RingtoneManager {
createLocalMediaPlayer);
}
//FIXME bypass the notion of stream types within the class
/**
* Returns a {@link Ringtone} with {@link VolumeShaper} if required 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 volumeShaperConfig config for volume shaper of the ringtone if applied.
* @see #getRingtone(Context, Uri)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
@Nullable VolumeShaper.Configuration volumeShaperConfig,
boolean createLocalMediaPlayer) {
@@ -776,7 +766,10 @@ public class RingtoneManager {
r.setVolumeShaperConfig(volumeShaperConfig);
r.setUri(ringtoneUri, volumeShaperConfig);
if (createLocalMediaPlayer) {
r.createLocalMediaPlayer();
if (!r.createLocalMediaPlayer()) {
Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
return null;
}
}
return r;
} catch (Exception ex) {
@@ -1158,24 +1151,38 @@ public class RingtoneManager {
}
// Try finding the scanned ringtone
final String filename = getDefaultRingtoneFilename(type);
final String whichAudio = getQueryStringForType(type);
final String where = MediaColumns.DISPLAY_NAME + "=? AND " + whichAudio + "=?";
final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
try (Cursor cursor = context.getContentResolver().query(baseUri,
new String[] { MediaColumns._ID },
where,
new String[] { filename, "1" }, null)) {
if (cursor.moveToFirst()) {
final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse(
ContentUris.withAppendedId(baseUri, cursor.getLong(0)));
RingtoneManager.setActualDefaultRingtoneUri(context, type, ringtoneUri);
Settings.System.putInt(context.getContentResolver(), setting, 1);
}
Uri ringtoneUri = computeDefaultRingtoneUri(context, type);
if (ringtoneUri != null) {
RingtoneManager.setActualDefaultRingtoneUri(context, type, ringtoneUri);
Settings.System.putInt(context.getContentResolver(), setting, 1);
}
}
}
/**
* @param type the type of ringtone (e.g {@link #TYPE_RINGTONE})
* @return the system default URI if found, null otherwise.
*/
private static Uri computeDefaultRingtoneUri(@NonNull Context context, int type) {
// Try finding the scanned ringtone
final String filename = getDefaultRingtoneFilename(type);
final String whichAudio = getQueryStringForType(type);
final String where = MediaColumns.DISPLAY_NAME + "=? AND " + whichAudio + "=?";
final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
try (Cursor cursor = context.getContentResolver().query(baseUri,
new String[] { MediaColumns._ID },
where,
new String[] { filename, "1" }, null)) {
if (cursor.moveToFirst()) {
final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse(
ContentUris.withAppendedId(baseUri, cursor.getLong(0)));
return ringtoneUri;
}
}
return null;
}
private static String getDefaultRingtoneSetting(int type) {
switch (type) {
case TYPE_RINGTONE: return "ringtone_set";