1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 12:56:49 +01:00

Add support for exclusive audio focus

This pauses temporarily other apps that are playing sound while our notifications get spoken.
This commit is contained in:
Daniele Gobbetti 2024-05-14 16:06:03 +02:00
parent 9ba96231c3
commit 9c68acce2e
6 changed files with 50 additions and 3 deletions

View File

@ -460,6 +460,7 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_AUTO_REPLY_INCOMING_CALL = "pref_auto_reply_phonecall";
public static final String PREF_AUTO_REPLY_INCOMING_CALL_DELAY = "pref_auto_reply_phonecall_delay";
public static final String PREF_SPEAK_NOTIFICATIONS_ALOUD = "pref_speak_notifications_aloud";
public static final String PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE = "pref_speak_notifications_focus_exclusive";
public static final String PREF_CYCLING_SENSOR_PERSISTENCE_INTERVAL = "pref_cycling_persistence_interval";
public static final String PREF_CYCLING_SENSOR_WHEEL_DIAMETER = "pref_cycling_wheel_diameter";

View File

@ -646,6 +646,8 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor(PREF_CYCLING_SENSOR_PERSISTENCE_INTERVAL);
addPreferenceHandlerFor(PREF_CYCLING_SENSOR_WHEEL_DIAMETER);
addPreferenceHandlerFor(PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE);
addPreferenceHandlerFor("lock");
String sleepTimeState = prefs.getString(PREF_SLEEP_TIME, PREF_DO_NOT_DISTURB_OFF);

View File

@ -17,6 +17,7 @@
package nodomain.freeyourgadget.gadgetbridge.service;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
@ -31,6 +32,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.util.GBTextToSpeech;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE;
public abstract class AbstractHeadphoneDeviceSupport extends AbstractSerialDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(AbstractHeadphoneDeviceSupport.class);
private GBTextToSpeech gbTextToSpeech;
@ -94,10 +97,26 @@ public abstract class AbstractHeadphoneDeviceSupport extends AbstractSerialDevic
@Override
public boolean connect() {
getDeviceIOThread().start();
gbTextToSpeech = new GBTextToSpeech(getContext(), new UtteranceProgressListener());
final SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
gbTextToSpeech = new GBTextToSpeech(getContext(), new UtteranceProgressListener(),
prefs.getBoolean(PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE, false) ?
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE :
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
);
return true;
}
@Override
public void onSendConfiguration(String config) {
LOG.warn("ONSENDCONFIGURATION");
if (PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE.equals(config)) {
final SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
gbTextToSpeech.setAudioFocus(prefs.getBoolean(PREF_SPEAK_NOTIFICATIONS_FOCUS_EXCLUSIVE, false) ?
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE :
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
}
}
@Override
public void dispose() {
gbTextToSpeech.shutdown();
@ -113,6 +132,8 @@ public abstract class AbstractHeadphoneDeviceSupport extends AbstractSerialDevic
@Override
public void onDone(String utteranceId) {
// LOG.debug("UtteranceProgressListener onDone.");
gbTextToSpeech.abandonFocus();
if (utteranceId.equals("call")) {
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
final int delayMillis = Integer.parseInt(prefs.getString(DeviceSettingsPreferenceConst.PREF_AUTO_REPLY_INCOMING_CALL_DELAY, "15")) * 1000;

View File

@ -17,10 +17,18 @@ public class GBTextToSpeech {
private final Context context;
private TextToSpeech textToSpeech;
private boolean isConnected = false;
private final AudioManager audioManager;
private int audioFocus;
public GBTextToSpeech(Context context, UtteranceProgressListener callback) {
public GBTextToSpeech(Context context, UtteranceProgressListener callback, int audioFocus) {
this.context = context;
initializeTTS(callback);
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
this.audioFocus = audioFocus;
}
public void setAudioFocus(int audioFocus) {
this.audioFocus = audioFocus;
}
public boolean isConnected() {
@ -51,6 +59,9 @@ public class GBTextToSpeech {
}
public void speakNotification(String text) {
int result = audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, this.audioFocus);
if (AudioManager.AUDIOFOCUS_REQUEST_GRANTED != result)
LOG.warn("AudioManager did not grant us the requested focus");
Bundle params = new Bundle();
params.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC);
textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, params, "notification");
@ -63,5 +74,7 @@ public class GBTextToSpeech {
}
}
public void abandonFocus() {
audioManager.abandonAudioFocus(null);
}
}

View File

@ -2807,6 +2807,9 @@
<string name="pref_auto_reply_calls_delay_title">Automatic Answer Delay</string>
<string name="pref_speak_notifications_aloud_summary">Notifications will be read aloud through the headphones</string>
<string name="pref_speak_notifications_aloud_title">Speak Notifications Aloud</string>
<string name="pref_speak_notifications_focus_exclusive_title">Pause audio of other applications</string>
<string name="pref_speak_notifications_focus_exclusive_summary_on">Playback from other applications will be paused while the notification is spoken</string>
<string name="pref_speak_notifications_focus_exclusive_summary_off">Playback volume of other applications will be lowered while the notification is spoken</string>
<string name="pref_header_calls_and_notifications">Calls and notifications</string>
<string name="pref_title_bottom_navigation_bar">Bottom navigation bar</string>
<string name="pref_summary_bottom_navigation_bar_on">Switch between main screens using the navigation bar or horizontal swiping</string>

View File

@ -22,4 +22,11 @@
android:key="pref_speak_notifications_aloud"
android:summary="@string/pref_speak_notifications_aloud_summary"
android:title="@string/pref_speak_notifications_aloud_title" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_voice"
android:key="pref_speak_notifications_focus_exclusive"
android:summaryOff="@string/pref_speak_notifications_focus_exclusive_summary_off"
android:summaryOn="@string/pref_speak_notifications_focus_exclusive_summary_on"
android:title="@string/pref_speak_notifications_focus_exclusive_title" />
</androidx.preference.PreferenceScreen>