webentwicklung-frage-antwort-db.com.de

Gibt es eine Broadcast-Aktion für Volumenänderungen?

Ich programmiere ein kleines Widget, das aktualisiert werden muss, wenn der Benutzer die Klingeltonlautstärke oder die Vibrationseinstellungen ändert.

Das Erfassen von Android.media.VIBRATE_SETTING_CHANGED funktioniert gut für die Vibrations-Einstellungen, aber ich habe keine Möglichkeit gefunden, benachrichtigt zu werden, wenn sich die Klingeltonlautstärke ändert, und obwohl ich versuchen könnte, zu erfassen, wann der Benutzer die Lautstärketasten drückt, gibt es viele andere Optionen zum Ändern der Lautstärke ohne Verwendung dieser Tasten.

Wissen Sie, ob für dieses Projekt eine Broadcast-Aktion definiert ist oder eine Möglichkeit besteht, eine zu erstellen oder das Problem ohne sie zu lösen?

47
LuTHieR

Es gibt keine Broadcast-Aktion, aber ich habe festgestellt, dass Sie einen Inhaltsbeobachter anschließen können, um benachrichtigt zu werden, wenn sich die Einstellungen ändern, wobei das Volumen der Streams einige dieser Einstellungen ist. Registrieren Sie sich für Android.provider.Settings.System.CONTENT_URI, um über alle Änderungen der Einstellungen informiert zu werden:

mSettingsContentObserver = new SettingsContentObserver( new Handler() ); 
this.getApplicationContext().getContentResolver().registerContentObserver( 
    Android.provider.Settings.System.CONTENT_URI, true, 
    mSettingsContentObserver );

Der Inhaltsbeobachter könnte ungefähr so ​​aussehen:

public class SettingsContentObserver extends ContentObserver {

   public SettingsContentObserver(Handler handler) {
      super(handler);
   } 

   @Override
   public boolean deliverSelfNotifications() {
      return super.deliverSelfNotifications(); 
   }

   @Override
   public void onChange(boolean selfChange) {
      super.onChange(selfChange);
      Log.v(LOG_TAG, "Settings change detected");
      updateStuff();
   }
}

Stellen Sie sicher, dass Sie den Inhaltsbeobachter zu einem bestimmten Zeitpunkt abmelden.

73
Nathan Totura

Nathans Code funktioniert, gibt jedoch zwei Benachrichtigungen für jede Systemänderungseinstellung aus. Um dies zu vermeiden, verwenden Sie Folgendes

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("Decreased");
            previousVolume=currentVolume;
        }
        else if(delta<0)
        {
            Logger.d("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);
60
Aditya

Ja, Sie können einen Receiver für eine Volume-Änderung registrieren (dies ist eine Art Hack, funktioniert aber). Ich habe es auf diese Weise geschafft (dies betrifft keinen ContentOb-Server): In manifest-XML-Datei:

<receiver Android:name="com.example.myproject.receivers.MyReceiver" >
     <intent-filter>
          <action Android:name="Android.media.VOLUME_CHANGED_ACTION" />
     </intent-filter>
</receiver>

Rundfunkempfänger:

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("Android.media.VOLUME_CHANGED_ACTION")) {
            Log.d("Music Stream", "has changed");       
        }
    }
}

ich hoffe es hilft!

11
alexm

Basierend auf Nathans , adis und swoobys Code erstellte ich ein vollständiges Funktionsbeispiel mit einigen geringfügigen Verbesserungen.

Wenn Sie die AudioFragment-Klasse betrachten, können Sie sehen, wie einfach es ist, auf Lautstärkeänderungen mit unserer benutzerdefinierten ContentObserver..__ zu hören.

public class AudioFragment extends Fragment implements OnAudioVolumeChangedListener {

    private AudioVolumeObserver mAudioVolumeObserver;

    @Override
    public void onResume() {
        super.onResume();
        // initialize audio observer
        if (mAudioVolumeObserver == null) {
            mAudioVolumeObserver = new AudioVolumeObserver(getActivity());
        }
        /*
         * register audio observer to identify the volume changes
         * of audio streams for music playback.
         *
         * It is also possible to listen for changes in other audio stream types:
         * STREAM_RING: phone ring, STREAM_ALARM: alarms, STREAM_SYSTEM: system sounds, etc.
         */
        mAudioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
    }

    @Override
    public void onPause() {
        super.onPause();
        // release audio observer
        if (mAudioVolumeObserver != null) {
            mAudioVolumeObserver.unregister();
        }
    }

    @Override
    public void onAudioVolumeChanged(int currentVolume, int maxVolume) {
        Log.d("Audio", "Volume: " + currentVolume + "/" + maxVolume);
        Log.d("Audio", "Volume: " + (int) ((float) currentVolume / maxVolume) * 100 + "%");
    }
}


public class AudioVolumeContentObserver extends ContentObserver {

    private final OnAudioVolumeChangedListener mListener;
    private final AudioManager mAudioManager;
    private final int mAudioStreamType;
    private int mLastVolume;

    public AudioVolumeContentObserver(
            @NonNull Handler handler,
            @NonNull AudioManager audioManager,
            int audioStreamType,
            @NonNull OnAudioVolumeChangedListener listener) {

        super(handler);
        mAudioManager = audioManager;
        mAudioStreamType = audioStreamType;
        mListener = listener;
        mLastVolume = audioManager.getStreamVolume(mAudioStreamType);
    }

    /**
     * Depending on the handler this method may be executed on the UI thread
     */
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        if (mAudioManager != null && mListener != null) {
            int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType);
            int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
            if (currentVolume != mLastVolume) {
                mLastVolume = currentVolume;
                mListener.onAudioVolumeChanged(currentVolume, maxVolume);
            }
        }
    }

    @Override
    public boolean deliverSelfNotifications() {
        return super.deliverSelfNotifications();
    }
}


public class AudioVolumeObserver {

    private final Context mContext;
    private final AudioManager mAudioManager;
    private AudioVolumeContentObserver mAudioVolumeContentObserver;

    public AudioVolumeObserver(@NonNull Context context) {
        mContext = context;
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    }

    public void register(int audioStreamType, 
                         @NonNull OnAudioVolumeChangedListener listener) {

        Handler handler = new Handler();
        // with this handler AudioVolumeContentObserver#onChange() 
        //   will be executed in the main thread
        // To execute in another thread you can use a Looper
        // +info: https://stackoverflow.com/a/35261443/904907

        mAudioVolumeContentObserver = new AudioVolumeContentObserver(
                handler,
                mAudioManager,
                audioStreamType,
                listener);

        mContext.getContentResolver().registerContentObserver(
                Android.provider.Settings.System.CONTENT_URI,
                true,
                mAudioVolumeContentObserver);
    }

    public void unregister() {
        if (mAudioVolumeContentObserver != null) {
            mContext.getContentResolver().unregisterContentObserver(mAudioVolumeContentObserver);
            mAudioVolumeContentObserver = null;
        }
    }
}


public interface OnAudioVolumeChangedListener {

    void onAudioVolumeChanged(int currentVolume, int maxVolume);
}

Hoffe, es ist immer noch nützlich für jemanden! :)

8
Ryan Amaral

Nathans und adis Code funktioniert, kann aber aufgeräumt und in sich geschlossen werden:

public class AudioStreamVolumeObserver
{
    public interface OnAudioStreamVolumeChangedListener
    {
        void onAudioStreamVolumeChanged(int audioStreamType, int volume);
    }

    private static class AudioStreamVolumeContentObserver
            extends ContentObserver
    {
        private final AudioManager                       mAudioManager;
        private final int                                mAudioStreamType;
        private final OnAudioStreamVolumeChangedListener mListener;

        private int mLastVolume;

        public AudioStreamVolumeContentObserver(
                @NonNull
                Handler handler,
                @NonNull
                AudioManager audioManager, int audioStreamType,
                @NonNull
                OnAudioStreamVolumeChangedListener listener)
        {
            super(handler);

            mAudioManager = audioManager;
            mAudioStreamType = audioStreamType;
            mListener = listener;

            mLastVolume = mAudioManager.getStreamVolume(mAudioStreamType);
        }

        @Override
        public void onChange(boolean selfChange)
        {
            int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);

            if (currentVolume != mLastVolume)
            {
                mLastVolume = currentVolume;

                mListener.onAudioStreamVolumeChanged(mAudioStreamType, currentVolume);
            }
        }
    }

    private final Context mContext;

    private AudioStreamVolumeContentObserver mAudioStreamVolumeContentObserver;

    public AudioStreamVolumeObserver(
            @NonNull
            Context context)
    {
        mContext = context;
    }

    public void start(int audioStreamType,
                      @NonNull
                      OnAudioStreamVolumeChangedListener listener)
    {
        stop();

        Handler handler = new Handler();
        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

        mAudioStreamVolumeContentObserver = new AudioStreamVolumeContentObserver(handler, audioManager, audioStreamType, listener);

        mContext.getContentResolver()
                .registerContentObserver(System.CONTENT_URI, true, mAudioStreamVolumeContentObserver);
    }

    public void stop()
    {
        if (mAudioStreamVolumeContentObserver == null)
        {
            return;
        }

        mContext.getContentResolver()
                .unregisterContentObserver(mAudioStreamVolumeContentObserver);
        mAudioStreamVolumeContentObserver = null;
    }
}
7
swooby

Hallo, ich habe den Code oben ausprobiert und er hat bei mir nicht funktioniert. Aber als ich versuchte, diese Zeile hinzuzufügen

getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);

und legen

mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(Android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );

Es funktioniert jetzt. Mein Anliegen ist, wie ich den Volume-Dialog beim Wechseln ausblenden kann. Siehe dieses image .

2
donmj

Wenn nur der Klingeltonmodus geändert wird, können Sie den Broadcast-Empfänger mit "Android.media.RINGER_MODE_CHANGED" als Aktion verwenden. Es wird leicht zu implementieren

2
user2503849
  private const val EXTRA_VOLUME_STREAM_TYPE = "Android.media.EXTRA_VOLUME_STREAM_TYPE"
  private const val VOLUME_CHANGED_ACTION = "Android.media.VOLUME_CHANGED_ACTION"

    val filter = IntentFilter(VOLUME_CHANGED_ACTION)
    filter.addAction(RINGER_MODE_CHANGED_ACTION)

      val receiver = object : BroadcastReceiver() {
            override fun onReceive(context1: Context, intent: Intent) {

                val stream = intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, UNKNOWN)
                val mode = intent.getIntExtra(EXTRA_RINGER_MODE, UNKNOWN)
                val volumeLevel = audioManager.getStreamVolume(stream)
            }
        }
1
Ken Zira

100% Arbeitsweise in allen Fällen

  public class SettingsContentObserver extends ContentObserver {

        SettingsContentObserver(Handler handler) {
            super(handler);
        }

        @Override
        public boolean deliverSelfNotifications() {
            return super.deliverSelfNotifications();
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            volumeDialogContract.updateMediaVolume(getMediaVolume());


    }

    int getMediaVolume() {
        return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
    }



    void unRegisterVolumeChangeListener() {
        volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().
                unregisterContentObserver(settingsContentObserver);
    }

    void registerVolumeChangeListener() {
        settingsContentObserver = new VolumeDialogPresenter.SettingsContentObserver(new Handler());
        volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().registerContentObserver(
                Android.provider.Settings.System.CONTENT_URI, true,
                settingsContentObserver);
    }
0
Vinayak