1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-28 19:45:50 +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.session.MediaController;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.SystemClock;
import android.view.KeyEvent;
@ -35,6 +36,7 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class GBMusicControlReceiver extends BroadcastReceiver {
@ -43,13 +45,13 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
public static final String ACTION_MUSICCONTROL = "nodomain.freeyourgadget.gadgetbridge.musiccontrol";
@Override
public void onReceive(Context context, Intent intent) {
GBDeviceEventMusicControl.Event musicCmd = GBDeviceEventMusicControl.Event.values()[intent.getIntExtra("event", 0)];
int keyCode = -1;
int volumeAdjust = AudioManager.ADJUST_LOWER;
public void onReceive(final Context context, final Intent intent) {
final int event = intent.getIntExtra("event", 0);
final GBDeviceEventMusicControl.Event musicCmd = GBDeviceEventMusicControl.Event.values()[event];
final int keyCode;
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
switch (musicCmd) {
case NEXT:
keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
@ -73,70 +75,144 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
break;
case VOLUMEUP:
// change default and fall through, :P
volumeAdjust = AudioManager.ADJUST_RAISE;
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
sendPhoneVolume(audioManager);
return;
case VOLUMEDOWN:
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, volumeAdjust, 0);
final int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
final int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
final int volumePercentage = (byte) Math.round(100 * (volumeLevel / (float) volumeMax));
GBApplication.deviceService().onSetPhoneVolume(volumePercentage);
break;
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0);
sendPhoneVolume(audioManager);
return;
default:
LOG.error("Unknown event {}", event);
return;
}
if (keyCode != -1) {
String audioPlayer = getAudioPlayer(context);
final GBPrefs prefs = GBApplication.getPrefs();
LOG.debug("keypress: " + musicCmd.toString() + " sent to: " + audioPlayer);
if (prefs.getBoolean("pref_deprecated_media_control", false)) {
// Deprecated path - mb_intents works for some players and not others, and vice-versa
long eventtime = SystemClock.uptimeMillis();
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);
final long eventTime = SystemClock.uptimeMillis();
if (prefs.getBoolean("mb_intents", false)) {
String audioPlayer = getAudioPlayer(context);
LOG.debug("Sending key press {} to {}", musicCmd, audioPlayer);
final Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0);
downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent);
if (!"default".equals(audioPlayer)) {
downIntent.setPackage(audioPlayer);
}
context.sendOrderedBroadcast(downIntent, null);
Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, keyCode, 0);
final Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0);
upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent);
if (!"default".equals(audioPlayer)) {
upIntent.setPackage(audioPlayer);
}
context.sendOrderedBroadcast(upIntent, null);
} 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);
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);
}
} 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) {
Prefs prefs = GBApplication.getPrefs();
String audioPlayer = prefs.getString("audio_player", "default");
MediaSessionManager mediaSessionManager =
(MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
private static void sendPhoneVolume(final AudioManager audioManager) {
final int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
final int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
final int volumePercentage = (byte) Math.round(100 * (volumeLevel / (float) volumeMax));
GBApplication.deviceService().onSetPhoneVolume(volumePercentage);
}
@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 {
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);
final List<MediaController> controllers = mediaSessionManager.getActiveSessions(
new ComponentName(context, NotificationListener.class)
);
if (controllers.isEmpty()) {
LOG.warn("No media controller available");
return audioPlayer;
}
} catch (SecurityException e) {
return controllers.get(0).getPackageName();
} catch (final SecurityException 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;

View File

@ -3234,4 +3234,8 @@
<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_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>

View File

@ -42,22 +42,6 @@
android:title="@string/pref_title_bottom_navigation_bar"
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
android:key="pref_category_dashboard"
android:title="@string/bottom_nav_dashboard"
@ -403,4 +387,49 @@
app:iconSpaceReserved="false" />
</PreferenceCategory>
</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>