web-dev-qa-db-de.com

Lautstärketasten im Hintergrunddienst anhören?

Ich weiß, wie man Lautstärketasten in einer Aktivität hört. Aber kann ich das im Hintergrund machen? Wenn ja, wie geht das?

37
user942821

Gemessen an den paar anderen Fragen zu diesem Thema, nein.

Andere Frage 1 , Andere Frage 2

Dienste erhalten einfach keine KeyEvent-Rückrufe.

10
Tanis.7x

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()
29
ssuukk

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?

19
Joe

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:

  • Die Lautstärketasten werden abgefangen vollständig. Während dieser Code ausgeführt wird, können Sie die Ruftonlautstärke nicht mit den Lautstärketasten einstellen. Dies könnte behoben werden, ich habe es einfach nicht versucht.
  • Wenn Sie das Beispiel unverändert ausführen, werden die Lautstärketasten auch dann von der App gesteuert, wenn der Bildschirm ausgeschaltet ist und die App aus der Liste "Zuletzt verwendete Apps" entfernt wurde. Du musst gehen zu Settings->Applications, finde die App und stoppe sie, um die Lautstärketasten wieder zu aktivieren.
7
Denis Kniazhev

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

Schritte

1. Legen Sie blank.mp3 im RAW-Ordner ab (Download von hier )

2. Medien unter onStartCommand () starten

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;
}

3. Sie müssen den Mediaplayer stoppen und freigeben. Es ist besser, dies in onDestroy () zu tun.

@Override
public void onDestroy() {

    mediaPlayer.stop();
    mediaPlayer.release();

    super.onDestroy();
}

4. Erstellen Sie einen Broadcast-Empfänger, der die Lautstärke überwacht

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;
        }
    }
};

5. Registrieren Sie den Broadcast-Empfänger in onStartCommand ().

@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;
}

6. Heben Sie die Registrierung des Broadccast-Empfängers in onDestroy () auf.

 @Override
public void onDestroy() {
    .....

    unregisterReceiver(broadcastReceiver);

    .....

    super.onDestroy();
}

Das ist alles

2
Bikram Pandit

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);
    }
0
Maurice Gavin

Dies erfordert Lollipop (v5.0/API 21) oder höher

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();
        }
    }
}
0
Gibolt

In diesem Fall dokumentiert Android keine APIs für die Interaktion mit Lautstärketasten. Ich denke, die Antwort ist nein…

0
Lincoln Hawk

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.

Lösungen

1) MediaSession (vom Service)

Antwort von Denis Kniazhev: https://stackoverflow.com/a/43304591/2441655

Nachteile:
1. Benötigt Android SDK 21+ (Android 9+).

2) 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%.

3) 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%.

4) AudioManager.registerMediaButtonEventReceiver (vom Service)

Antwort von Joe: https://stackoverflow.com/a/11510564/2441655

Nachteile:
1. Funktioniert bei den meisten Roms nicht: Kommentar von elgui

5) 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.

6) 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.

Fazit

Die Lösung, die ich derzeit verwende, ist die Nummer 1, weil:

  1. Es ist ein offizieller Teil des SDK.
  2. Es ist von einem Dienst verwendbar. (dh unabhängig davon, in welcher App du bist)
  3. Es erfasst jeden Tastendruck, unabhängig von der aktuellen Lautstärke/dem aktuellen UI-Status.
  4. Es funktioniert, wenn der Bildschirm ausgeschaltet ist.

Lassen Sie mich wissen, ob Sie andere finden - oder ob Sie bei einigen von ihnen weitere Nachteile festgestellt haben!

0
Venryx

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.

0
Ashish