¿Hay una acción de transmisión para cambios de volumen?

Estoy progtwigndo un pequeño widget que necesita ser actualizado cada vez que el usuario cambia el volumen del timbre o la configuración de vibración.

La captura de android.media.VIBRATE_SETTING_CHANGED funciona bien para la configuración de vibración, pero no he encontrado ninguna forma de recibir notificaciones cuando cambia el volumen del timbre y aunque podría intentar capturar cuando el usuario presiona las teclas físicas subir / bajar volumen, hay muchas otras opciones para cambiar el volumen sin usar estas teclas.

¿Sabes si hay alguna acción de difusión definida para esto o de alguna manera para crear una o para resolver el problema sin ella?

    No hay acción de transmisión, pero encontré que puede conectar un observador de contenido para recibir una notificación cuando la configuración cambia, y el volumen de las transmisiones es una de esas configuraciones. Regístrese para android.provider.Settings.System.CONTENT_URI para recibir notificaciones de todos los cambios de configuración:

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

    El observador de contenido podría verse más o menos así:

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

    Y asegúrese de anular el registro del contenido del observador en algún momento.

    El código de Nathan funciona pero da dos notificaciones para cada configuración de sistema de cambio. Para evitar eso, use la siguiente

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

    Luego, en su servicio en Crear, regístrelo con:

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

    Luego anule el registro en onDestroy:

     getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver); 

    Sí, puede registrar un receptor para un cambio de volumen (esto es una especie de truco, pero funciona), logré hacerlo de esta manera (no implica un ContentObserver): en el archivo xml de manifiesto:

          

    Receptor de radiodifusión:

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

    ¡Espero eso ayude!

    Basado en el código de Nathan’s , adi’s y swooby, creé un ejemplo de trabajo completo con algunas mejoras menores.

    En cuanto a la clase AudioFragment , podemos ver lo fácil que es escuchar los cambios de volumen con nuestro ContentObserver personalizado.

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

    ¡Espero que todavía sea útil para alguien! 🙂

    El código de Nathan y Adi funciona, pero se puede limpiar y autocontenido para:

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

    Hola, probé el código anterior y no funcionó para mí. Pero cuando traté de agregar esta línea

     getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); 

    y pon

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

    Ahora funciona. Mi preocupación es cómo ocultar el diálogo de volumen en el cambio. Ver esta imagen

    Si solo cambia el modo de timbre, puede usar el receptor Brodcast con ” android.media.RINGER_MODE_CHANGED ” como acción. Será fácil de implementar

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