1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-09 03:37:03 +01:00

Use MediaController for media buttons

This commit is contained in:
José Rebelo 2024-08-28 17:33:37 +01:00 committed by José Rebelo
parent c7bb47d6bd
commit 95fdee3cbe
3 changed files with 166 additions and 57 deletions

View File

@ -24,6 +24,7 @@ import android.content.Intent;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.session.MediaController; import android.media.session.MediaController;
import android.media.session.MediaSessionManager; import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.SystemClock; import android.os.SystemClock;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -35,6 +36,7 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener; import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class GBMusicControlReceiver extends BroadcastReceiver { public class GBMusicControlReceiver extends BroadcastReceiver {
@ -43,12 +45,12 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
public static final String ACTION_MUSICCONTROL = "nodomain.freeyourgadget.gadgetbridge.musiccontrol"; public static final String ACTION_MUSICCONTROL = "nodomain.freeyourgadget.gadgetbridge.musiccontrol";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(final Context context, final Intent intent) {
GBDeviceEventMusicControl.Event musicCmd = GBDeviceEventMusicControl.Event.values()[intent.getIntExtra("event", 0)]; final int event = intent.getIntExtra("event", 0);
int keyCode = -1; final GBDeviceEventMusicControl.Event musicCmd = GBDeviceEventMusicControl.Event.values()[event];
int volumeAdjust = AudioManager.ADJUST_LOWER; final int keyCode;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
switch (musicCmd) { switch (musicCmd) {
case NEXT: case NEXT:
@ -73,70 +75,144 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
break; break;
case VOLUMEUP: case VOLUMEUP:
// change default and fall through, :P audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
volumeAdjust = AudioManager.ADJUST_RAISE; sendPhoneVolume(audioManager);
return;
case VOLUMEDOWN: case VOLUMEDOWN:
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, volumeAdjust, 0); audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0);
sendPhoneVolume(audioManager);
final int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); return;
final int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
final int volumePercentage = (byte) Math.round(100 * (volumeLevel / (float) volumeMax));
GBApplication.deviceService().onSetPhoneVolume(volumePercentage);
break;
default: default:
LOG.error("Unknown event {}", event);
return; return;
} }
if (keyCode != -1) { final GBPrefs prefs = GBApplication.getPrefs();
if (prefs.getBoolean("pref_deprecated_media_control", false)) {
// Deprecated path - mb_intents works for some players and not others, and vice-versa
final long eventTime = SystemClock.uptimeMillis();
if (prefs.getBoolean("mb_intents", false)) {
String audioPlayer = getAudioPlayer(context); String audioPlayer = getAudioPlayer(context);
LOG.debug("keypress: " + musicCmd.toString() + " sent to: " + audioPlayer); LOG.debug("Sending key press {} to {}", musicCmd, audioPlayer);
long eventtime = SystemClock.uptimeMillis(); final Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0);
if (GBApplication.getPrefs().getBoolean("mb_intents", false)) {
Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, keyCode, 0);
downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent); downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent);
if (!"default".equals(audioPlayer)) { if (!"default".equals(audioPlayer)) {
downIntent.setPackage(audioPlayer); downIntent.setPackage(audioPlayer);
} }
context.sendOrderedBroadcast(downIntent, null); context.sendOrderedBroadcast(downIntent, null);
Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); final Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, keyCode, 0); final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0);
upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent); upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent);
if (!"default".equals(audioPlayer)) { if (!"default".equals(audioPlayer)) {
upIntent.setPackage(audioPlayer); upIntent.setPackage(audioPlayer);
} }
context.sendOrderedBroadcast(upIntent, null); context.sendOrderedBroadcast(upIntent, null);
} else { } else {
KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, keyCode, 0); LOG.debug("Sending key press {} generally", musicCmd);
final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0);
audioManager.dispatchMediaKeyEvent(downEvent); audioManager.dispatchMediaKeyEvent(downEvent);
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, keyCode, 0); final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0);
audioManager.dispatchMediaKeyEvent(upEvent); audioManager.dispatchMediaKeyEvent(upEvent);
} }
} else {
try {
final MediaSessionManager mediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
final List<MediaController> controllers = mediaSessionManager.getActiveSessions(
new ComponentName(context, NotificationListener.class)
);
if (controllers.isEmpty()) {
LOG.warn("No media controller found to handle {}", musicCmd);
return;
}
final MediaController controller = controllers.get(0);
switch (musicCmd) {
case NEXT:
controller.getTransportControls().skipToNext();
return;
case PREVIOUS:
controller.getTransportControls().skipToPrevious();
return;
case PLAY:
controller.getTransportControls().play();
return;
case PAUSE:
controller.getTransportControls().pause();
return;
case PLAYPAUSE:
final PlaybackState playbackState = controller.getPlaybackState();
if (playbackState != null) {
switch (playbackState.getState()) {
case PlaybackState.STATE_NONE:
case PlaybackState.STATE_STOPPED:
case PlaybackState.STATE_PAUSED:
case PlaybackState.STATE_FAST_FORWARDING:
case PlaybackState.STATE_REWINDING:
controller.getTransportControls().play();
return;
case PlaybackState.STATE_PLAYING:
controller.getTransportControls().pause();
return;
default:
return;
}
} else {
LOG.warn("Failed to determine playback state, attempting to play");
controller.getTransportControls().play();
}
return;
case REWIND:
controller.getTransportControls().rewind();
return;
case FORWARD:
controller.getTransportControls().fastForward();
}
} catch (final SecurityException e) {
LOG.warn("Failed to get media controller - did not grant notification access?", e);
} catch (final Exception e) {
LOG.error("Failed to get media controller", e);
}
} }
} }
private String getAudioPlayer(Context context) { private static void sendPhoneVolume(final AudioManager audioManager) {
Prefs prefs = GBApplication.getPrefs(); final int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
String audioPlayer = prefs.getString("audio_player", "default"); final int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
MediaSessionManager mediaSessionManager = final int volumePercentage = (byte) Math.round(100 * (volumeLevel / (float) volumeMax));
(MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
try { GBApplication.deviceService().onSetPhoneVolume(volumePercentage);
List<MediaController> controllers = mediaSessionManager.getActiveSessions(
new ComponentName(context, NotificationListener.class));
try {
MediaController controller = controllers.get(0);
audioPlayer = controller.getPackageName();
} catch (IndexOutOfBoundsException e) {
LOG.error("No media controller available", e);
} }
} catch (SecurityException e) {
@Deprecated
private static String getAudioPlayer(final Context context) {
final Prefs prefs = GBApplication.getPrefs();
final String audioPlayer = prefs.getString("audio_player", "default");
final MediaSessionManager mediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
try {
final List<MediaController> controllers = mediaSessionManager.getActiveSessions(
new ComponentName(context, NotificationListener.class)
);
if (controllers.isEmpty()) {
LOG.warn("No media controller available");
return audioPlayer;
}
return controllers.get(0).getPackageName();
} catch (final SecurityException e) {
LOG.warn("No permission to get media sessions - did not grant notification access?", e); LOG.warn("No permission to get media sessions - did not grant notification access?", e);
} catch (final Exception e) {
LOG.error("Failed to get media controller", e);
} }
return audioPlayer; return audioPlayer;

View File

@ -3234,4 +3234,8 @@
<string name="insufficient_space_for_upload">"Insufficient space for upload"</string> <string name="insufficient_space_for_upload">"Insufficient space for upload"</string>
<string name="smart_ring_measurement_error_worn_incorrectly">Measurement error. Are the ring\'s sensors oriented correctly?</string> <string name="smart_ring_measurement_error_worn_incorrectly">Measurement error. Are the ring\'s sensors oriented correctly?</string>
<string name="smart_ring_measurement_error_unknown">Unknown measurement error %d received from ring</string> <string name="smart_ring_measurement_error_unknown">Unknown measurement error %d received from ring</string>
<string name="pref_header_deprecated_functionalities">Deprecated functionalities</string>
<string name="pref_header_deprecated_functionalities_warning">The following functionalities have been deprecated and will be removed soon from the software.\nIf you need to enable one of the following settings be sure to get in touch with the project team.</string>
<string name="pref_deprecated_media_control_title">Deprecated media control</string>
<string name="pref_deprecated_media_control_summary">Send media control commands as key events instead of the media controller.</string>
</resources> </resources>

View File

@ -42,22 +42,6 @@
android:title="@string/pref_title_bottom_navigation_bar" android:title="@string/pref_title_bottom_navigation_bar"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="mb_intents"
android:layout="@layout/preference_checkbox"
android:summary="@string/pref_summary_mb_intents"
android:title="@string/pref_title_mb_intents"
app:iconSpaceReserved="false" />
<ListPreference
android:defaultValue="default"
android:dependency="mb_intents"
android:key="audio_player"
android:summary="%s"
android:title="@string/pref_title_audio_player"
app:iconSpaceReserved="false" />
<Preference <Preference
android:key="pref_category_dashboard" android:key="pref_category_dashboard"
android:title="@string/bottom_nav_dashboard" android:title="@string/bottom_nav_dashboard"
@ -403,4 +387,49 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen
android:key="pref_screen_deprecated_functionalities"
android:title="@string/pref_header_deprecated_functionalities"
app:iconSpaceReserved="false">
<PreferenceCategory
android:key="pref_key_deprecated_functionalities"
android:title="@string/pref_header_deprecated_functionalities_warning"
app:iconSpaceReserved="false"
app:singleLineTitle="false" />
<PreferenceCategory
android:key="pref_header_media_control"
android:title="@string/pref_deprecated_media_control_title"
app:iconSpaceReserved="false"
app:singleLineTitle="false">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_deprecated_media_control"
android:layout="@layout/preference_checkbox"
android:summary="@string/pref_deprecated_media_control_summary"
android:title="@string/pref_deprecated_media_control_title"
app:iconSpaceReserved="false" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:dependency="pref_deprecated_media_control"
android:key="mb_intents"
android:layout="@layout/preference_checkbox"
android:summary="@string/pref_summary_mb_intents"
android:title="@string/pref_title_mb_intents"
app:iconSpaceReserved="false" />
<ListPreference
android:defaultValue="default"
android:dependency="mb_intents"
android:key="audio_player"
android:summary="%s"
android:title="@string/pref_title_audio_player"
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>
</PreferenceScreen> </PreferenceScreen>