Есть ли трансляция для изменения объема?

Я программирую небольшой виджет, который необходимо обновлять, когда пользователь меняет громкость звонка или вибрирует настройки.

Захват android.media.VIBRATE_SETTING_CHANGED отлично подходит для настроек вибрации, но я не нашел способа получить уведомление, когда громкость звонка изменилась, и хотя я мог бы попытаться захватить, когда пользователь нажимает физические клавиши увеличения / уменьшения громкости, Есть много других вариантов изменения громкости без использования этих клавиш.

Знаете ли вы, есть ли какое-либо действие трансляции, определенное для этого или каким-либо способом создать его или решить проблему без него?

Solutions Collecting From Web of "Есть ли трансляция для изменения объема?"

Нет действия трансляции, но я обнаружил, что вы можете подключить наблюдателя контента, чтобы получать уведомления при изменении настроек, а объем потоков – некоторые из этих параметров. Зарегистрируйтесь для android.provider.Settings.System.CONTENT_URI, чтобы получать уведомления обо всех изменениях настроек:

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

Наблюдатель содержимого может выглядеть примерно так:

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

И обязательно отмените регистрацию контента в какой-то момент.

Код Натана работает, но дает два уведомления для каждой настройки системы изменений. Чтобы этого избежать, используйте следующие

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

Затем в вашем сервисе onCreate зарегистрируйте его с помощью:

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

Затем отмените регистрацию в onDestroy:

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

Да, вы можете зарегистрировать приемник для изменения тома (это своего рода хак, но работает), мне это удалось (не включает ContentObserver): в манифестном XML-файле:

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

BroadcastReceiver:

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

Надеюсь, поможет!

Код Натана и Ади работает, но может быть очищен и самодостаточен:

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

Привет, я пробовал код выше, и это не сработало для меня. Но когда я попытался добавить эту строку

 getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); 

и положи

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

Он работает сейчас. Моя забота заключается в том, как скрыть диалог громкости onchange. См. Это изображение .

Если изменяется его единственный режим звонка, вы можете использовать приемник Brodcast с « android.media.RINGER_MODE_CHANGED » в качестве действия. Это будет легко реализовать

Основанный на коде Nathan , adi и swooby, я создал полный рабочий пример с некоторыми незначительными улучшениями.

Глядя на класс AudioFragment мы можем видеть, насколько легко слушать изменения тома с помощью нашего настраиваемого ContentObserver .

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

Надеюсь, это по-прежнему полезно для кого-то! 🙂