Add interface to enable HapticGenerator for Ringtone.

HapticGenerator is an audio effect to generate haptic data from audio
data. An important usecase for HapticGenerator is ringtone. However, it
is not easy to use audio effect for the Ringtone class as the
Ringtone's lifecycle is different from AudioTrack/MediaPlayer. In that
case, add an interface in Ringtone to enable HapticGenerator. The
HapticGenerator will only be added if the effect is available for the
device.

Bug: 179080948
Test: atest RingtoneTest
Change-Id: Ia0416f6b6c6f311627be88dd9a57a989379ac947
This commit is contained in:
jiabin
2021-02-03 22:07:53 +00:00
committed by Jiabin Huang
parent 77bb0b7291
commit 835a332638
4 changed files with 50 additions and 3 deletions

View File

@@ -22978,10 +22978,12 @@ package android.media {
method @Deprecated public int getStreamType();
method public String getTitle(android.content.Context);
method public float getVolume();
method public boolean isHapticGeneratorEnabled();
method public boolean isLooping();
method public boolean isPlaying();
method public void play();
method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
method public boolean setHapticGeneratorEnabled(boolean);
method public void setLooping(boolean);
method @Deprecated public void setStreamType(int);
method public void setVolume(float);

View File

@@ -33,7 +33,8 @@ interface IRingtonePlayer {
float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig);
oneway void stop(IBinder token);
boolean isPlaying(IBinder token);
oneway void setPlaybackProperties(IBinder token, float volume, boolean looping);
oneway void setPlaybackProperties(IBinder token, float volume, boolean looping,
boolean hapticGeneratorEnabled);
/** Used for Notification sound playback. */
oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);

View File

@@ -24,6 +24,7 @@ import android.content.Context;
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;
@@ -77,6 +78,7 @@ public class Ringtone {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private MediaPlayer mLocalPlayer;
private final MyOnCompletionListener mCompletionListener = new MyOnCompletionListener();
private HapticGenerator mHapticGenerator;
@UnsupportedAppUsage
private Uri mUri;
@@ -89,6 +91,7 @@ public class Ringtone {
// 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} */
@@ -196,6 +199,34 @@ public class Ringtone {
}
}
/**
* 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
*/
@@ -203,9 +234,16 @@ public class Ringtone {
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);
mRemotePlayer.setPlaybackProperties(
mRemoteToken, mVolume, mIsLooping, mHapticGeneratorEnabled);
} catch (RemoteException e) {
Log.w(TAG, "Problem setting playback properties: ", e);
}
@@ -413,6 +451,10 @@ public class Ringtone {
private void destroyLocalPlayer() {
if (mLocalPlayer != null) {
if (mHapticGenerator != null) {
mHapticGenerator.release();
mHapticGenerator = null;
}
mLocalPlayer.setOnCompletionListener(null);
mLocalPlayer.reset();
mLocalPlayer.release();

View File

@@ -163,7 +163,8 @@ public class RingtonePlayer extends SystemUI {
}
@Override
public void setPlaybackProperties(IBinder token, float volume, boolean looping) {
public void setPlaybackProperties(IBinder token, float volume, boolean looping,
boolean hapticGeneratorEnabled) {
Client client;
synchronized (mClients) {
client = mClients.get(token);
@@ -171,6 +172,7 @@ public class RingtonePlayer extends SystemUI {
if (client != null) {
client.mRingtone.setVolume(volume);
client.mRingtone.setLooping(looping);
client.mRingtone.setHapticGeneratorEnabled(hapticGeneratorEnabled);
}
// else no client for token when setting playback properties but will be set at play()
}