Ich weiß, wie man Lautstärketasten in einer Aktivität hört. Aber kann ich das im Hintergrund machen? Wenn ja, wie geht das?
Gemessen an den paar anderen Fragen zu diesem Thema, nein.
Andere Frage 1 , Andere Frage 2
Dienste erhalten einfach keine KeyEvent-Rückrufe.
IT IS MÖGLICH. Verwenden Sie den folgenden Code (FÜR NEUERE ANDROIDS, ESP. Marshmallow, SIEHE UNTEN DER ANTWORT):
public class SettingsContentObserver extends ContentObserver {
int previousVolume;
Context context;
public SettingsContentObserver(Context c, Handler handler) {
super(handler);
context=c;
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta=previousVolume-currentVolume;
if(delta>0)
{
Logger.d("Ściszył!"); // volume decreased.
previousVolume=currentVolume;
}
else if(delta<0)
{
Logger.d("Zrobił głośniej!"); // volume increased.
previousVolume=currentVolume;
}
}
}
Dann in Ihrem Dienst beiCreate registrieren Sie es mit:
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(Android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
Dann die Registrierung in onDestroy aufheben:
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
Beachten Sie, dass in diesem Beispiel die Änderung des Medienvolumens beurteilt wird. Wenn Sie ein anderes Volume verwenden möchten, ändern Sie es!
AKTUALISIEREN:
Die obige Methode funktioniert angeblich nicht mit Marshmallow, ABER es gibt jetzt einen viel besseren Weg seit der Einführung von MediaSession! Sie müssen also zunächst Ihren Code in das MediaController/MediaSession-Muster migrieren und dann diesen Code verwenden:
private VolumeProviderCompat myVolumeProvider = null;
myVolumeProvider = new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
@Override
public void onAdjustVolume(int direction) {
// <0 volume down
// >0 volume up
}
};
mSession.setPlaybackToRemote(myVolumeProvider);
Das Drücken der Lautstärke wird auch bei ausgeschaltetem Bildschirm erkannt (registrieren Sie sich unbedingt, wenn Sie den richtigen Media-Tastenempfänger für Ihre Plattform verwenden!).
UPDATE 2, seit GalDude einige weitere Informationen zum Abrufen von MediaSession/MediaController angefordert hat. Sorry, aber da ich Java nicht mehr verwendet habe, wird es in Kotlin sein:
lateinit var mediaSession: MediaSessionCompat // you have to initialize it in your onCreate method
val kontroler: MediaControllerCompat
get() = mediaSession.controller // in Java it's just getController() on mediaSession
// in your onCreate/start method:
mediaSession = MediaSessionCompat(this, "YourPlayerName", receiver, null)
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
mediaSession.isActive = true
if (ratingIsWorking) // note: rating crashes on some machines you have to check it!
mediaSession.setRatingType(RatingCompat.RATING_5_STARS)
mediaSession.setCallback(object : MediaSessionCompat.Callback() {
...
// here you have to implement what happens with your player when play/pause/stop/ffw etc. is requested - see exaples elsewhere
})
// onDestroy/exit method:
mediaSession.isActive = false
mediaSession.release()
Die AOSP Music-App verfügt über einen Dienst ( MediaPlaybackService ), der auf Volume-Key-Ereignisse reagiert, indem er einen BroadcastReceiver ( MediaButtonIntentReceiver ) registriert.
Hier ist der Code-Ausschnitt, in dem der Empfänger registriert wird:
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
ComponentName rec = new ComponentName(getPackageName(),
MediaButtonIntentReceiver.class.getName());
mAudioManager.registerMediaButtonEventReceiver(rec);
Vergessen Sie auch nicht das Manifest:
<receiver Android:name="com.Android.music.MediaButtonIntentReceiver">
<intent-filter>
<action Android:name="Android.intent.action.MEDIA_BUTTON" />
<action Android:name="Android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
Dies funktioniert auch, wenn sich die Musik-App nicht im Vordergrund befindet. Wollen Sie das nicht?
Ich konnte es auf Android 5+ Geräten mit MediaSession
zum Laufen bringen. Allerdings funktionierte ContentObserver
, das von @ssuukk vorgeschlagen wurde, auf beiden 4.4 nicht für mich und 7.0-Geräte (zumindest auf ROMs, auf denen ich getestet habe). Hier ist ein vollständiges Beispiel, das mit Android 5+) funktioniert.
Bedienung:
import Android.app.Service;
import Android.content.Intent;
import Android.os.IBinder;
import Android.support.v4.media.VolumeProviderCompat;
import Android.support.v4.media.session.MediaSessionCompat;
import Android.support.v4.media.session.PlaybackStateCompat;
public class PlayerService extends Service {
private MediaSessionCompat mediaSession;
@Override
public void onCreate() {
super.onCreate();
mediaSession = new MediaSessionCompat(this, "PlayerService");
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 0) //you simulate a player which plays something.
.build());
//this will only work on Lollipop and up, see https://code.google.com/p/Android/issues/detail?id=224134
VolumeProviderCompat myVolumeProvider =
new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, /*max volume*/100, /*initial volume level*/50) {
@Override
public void onAdjustVolume(int direction) {
/*
-1 -- volume down
1 -- volume up
0 -- volume button released
*/
}
};
mediaSession.setPlaybackToRemote(myVolumeProvider);
mediaSession.setActive(true);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
mediaSession.release();
}
}
Im AndroidManifest.xml
:
<application ...>
...
<service Android:name=".PlayerService"/>
</application>
In Ihrer Tätigkeit:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
startService(new Intent(this, PlayerService.class));
}
Es gibt mehrere Dinge zu beachten:
Settings->Applications
, finde die App und stoppe sie, um die Lautstärketasten wieder zu aktivieren.Sie müssen einen leeren Ton des Dienstes wiedergeben, dann können Sie nur die Lautstärkeänderungen hören. Folgendes arbeitete für mich
private MediaPlayer mediaPlayer;
public MyService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
........
mediaPlayer = MediaPlayer.create(this, R.raw.blank);
mediaPlayer.setLooping(true);
mediaPlayer.start();
.......
return START_STICKY;
}
@Override
public void onDestroy() {
mediaPlayer.stop();
mediaPlayer.release();
super.onDestroy();
}
int volumePrev = 0;
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if ("Android.media.VOLUME_CHANGED_ACTION".equals(intent.getAction())) {
int volume = intent.getIntExtra("Android.media.EXTRA_VOLUME_STREAM_VALUE",0);
Log.i(TAG, "volume = " + volume);
if (volumePrev < volume) {
Log.i(TAG, "You have pressed volume up button");
} else {
Log.i(TAG, "You have pressed volume down button");
}
volumePrev = volume;
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
.....
IntentFilter filter = new IntentFilter();
filter.addAction("Android.media.VOLUME_CHANGED_ACTION");
registerReceiver(broadcastReceiver, filter);
....
return START_STICKY;
}
@Override
public void onDestroy() {
.....
unregisterReceiver(broadcastReceiver);
.....
super.onDestroy();
}
Hinweis: Dies funktioniert nur für Aktivitäten und nicht für Services, wie in der Frage angegeben.
Abhängig von dem Kontext, in dem der Rückruf erforderlich ist, ist möglicherweise eine alternative Lösung verfügbar.
Um die Lautstärketaste erkennen zu können, müsste eine Aktivität die dispatchKeyEvent
-Funktion überschreiben. Um in mehreren Aktivitäten vorhanden zu sein, könnte eine Oberklasse geschrieben werden, die die überschriebene Funktion enthält, die um alle nachfolgenden Aktivitäten erweitert wird.
Hier ist der Code zum Erkennen der Lautstärke-Auf/Ab-Taste:
// Over-ride this function to define what should happen when keys are pressed (e.g. Home button, Back button, etc.)
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_DOWN)
{
switch (event.getKeyCode())
{
case KeyEvent.KEYCODE_VOLUME_UP:
// Volume up key detected
// Do something
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
// Volume down key detected
// Do something
return true;
}
}
return super.dispatchKeyEvent(event);
}
Mein Ziel war es, das Systemvolumen eines Dienstes anzupassen. Jede Aktion kann jedoch auch in der Presse durchgeführt werden.
public class VolumeKeyController {
private MediaSessionCompat mMediaSession;
private final Context mContext;
public VolumeKeyController(Context context) {
mContext = context;
}
private void createMediaSession() {
mMediaSession = new MediaSessionCompat(mContext, KeyUtil.log);
mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mMediaSession.setPlaybackState(new Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
.build());
mMediaSession.setPlaybackToRemote(getVolumeProvider());
mMediaSession.setActive(true);
}
private VolumeProviderCompat getVolumeProvider() {
final AudioManager audio = mContext.getSystemService(Context.AUDIO_SERVICE);
int STREAM_TYPE = AudioManager.STREAM_MUSIC;
int currentVolume = audio.getStreamVolume(STREAM_TYPE);
int maxVolume = audio.getStreamMaxVolume(STREAM_TYPE);
final int VOLUME_UP = 1;
final int VOLUME_DOWN = -1;
return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
@Override
public void onAdjustVolume(int direction) {
// Up = 1, Down = -1, Release = 0
// Replace with your action, if you don't want to adjust system volume
if (direction == VOLUME_UP) {
audio.adjustStreamVolume(STREAM_TYPE,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
}
else if (direction == VOLUME_DOWN) {
audio.adjustStreamVolume(STREAM_TYPE,
AudioManager.ADJUST_LOWER, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
}
setCurrentVolume(audio.getStreamVolume(STREAM_TYPE));
}
};
}
// Call when control needed, add a call to constructor if needed immediately
public void setActive(boolean active) {
if (mMediaSession != null) {
mMediaSession.setActive(active);
return;
}
createMediaSession();
}
// Call from Service's onDestroy method
public void destroy() {
if (mMediaSession != null) {
mMediaSession.release();
}
}
}
In diesem Fall dokumentiert Android keine APIs für die Interaktion mit Lautstärketasten. Ich denke, die Antwort ist nein…
Leider ist dies ein weiterer Bereich von Android), in dem es wie fünf verschiedene Möglichkeiten gibt, "das Problem zu lösen", aber die meisten von ihnen funktionieren nicht sehr gut. Für meine eigene Gesundheit werde ich Versuchen Sie, alle verschiedenen Ansätze unten aufzulisten.
MediaSession
(vom Service)Antwort von Denis Kniazhev: https://stackoverflow.com/a/43304591/2441655
Nachteile:
1. Benötigt Android SDK 21+ (Android 9+).
Android.media.VOLUME_CHANGED_ACTION
(vom Service)Antwort von Nikhil: https://stackoverflow.com/a/44040282/2441655
Nachteile:
1. Kein offizieller Teil des SDK: https://stackoverflow.com/a/8974510/2441655
2. Ignoriert das erste Drücken der Lautstärketaste (da nur die Lautstärkeleiste angezeigt wird).
3. Ignoriert die Lauter-Taste bei 100% und die Leiser-Taste bei 0%.
ContentObserver
(vom Service)Antwort von ssuukk: https://stackoverflow.com/a/15292255/2441655 (erster Teil)
Nachteile:
1. Funktioniert nicht in neueren Versionen von Android: Kommentar von dsemi
2. Ignoriert das erste Drücken der Lautstärketaste (da nur die Lautstärkeleiste angezeigt wird).
3. Ignoriert die Lauter-Taste bei 100% und die Leiser-Taste bei 0%.
AudioManager.registerMediaButtonEventReceiver
(vom Service)Antwort von Joe: https://stackoverflow.com/a/11510564/2441655
Nachteile:
1. Funktioniert bei den meisten Roms nicht: Kommentar von elgui
onKeyDown
(aus Aktivität)Antwort von dipali: https://stackoverflow.com/a/21086563/2441655
Nachteile:
1. Funktioniert nicht, wenn der Bildschirm ausgeschaltet ist, in einer anderen App usw.
dispatchKeyEvent
(aus Aktivität)Antwort von Maurice Gavin: https://stackoverflow.com/a/11462962/2441655
Nachteile:
1. Funktioniert nicht, wenn der Bildschirm ausgeschaltet ist, in einer anderen App usw.
Die Lösung, die ich derzeit verwende, ist die Nummer 1, weil:
Lassen Sie mich wissen, ob Sie andere finden - oder ob Sie bei einigen von ihnen weitere Nachteile festgestellt haben!
checkout Lautstärke und Wiedergabe Ihrer App steuern ... Dies hilft, Ihr Problem zu lösen. Mehrere Anwendungen möchten möglicherweise das Drücken von Tasten aus dem Hintergrund hören. Dies kann der Grund dafür sein, dass KeyEvents nur von Activities as behandelt werden können Sie sind die Schnittstelle zum Benutzer, der die Tasten drückt.