From 835a332638af02d93df5090aa9c3d0221ae4182e Mon Sep 17 00:00:00 2001 From: jiabin Date: Wed, 3 Feb 2021 22:07:53 +0000 Subject: [PATCH] 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 --- core/api/current.txt | 2 + media/java/android/media/IRingtonePlayer.aidl | 3 +- media/java/android/media/Ringtone.java | 44 ++++++++++++++++++- .../systemui/media/RingtonePlayer.java | 4 +- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index e8174c0e3fe6d..19c3968875d38 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -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); diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl index 02fa94c845a6a..5a7ff7fbd1ae3 100644 --- a/media/java/android/media/IRingtonePlayer.aidl +++ b/media/java/android/media/IRingtonePlayer.aidl @@ -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); diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index bd783ce9f6b22..79d505ebbde88 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index 4c96de2328100..553b6d8679db3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -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() }