Merge "Reuse ringtone across multiple ringer operations"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2d4746d1aa
@@ -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)) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user