Есть ли широковещательное действие для изменения громкости? - PullRequest
49 голосов
/ 01 августа 2011

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

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

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

Ответы [ 9 ]

76 голосов
/ 11 августа 2011

Нет широковещательного действия, но я обнаружил, что вы можете подключить обозреватель контента, чтобы получать уведомления при изменении настроек, причем объем потоков является некоторыми из этих настроек. Зарегистрируйтесь для 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();
   }
}

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

61 голосов
/ 01 июля 2013

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

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);
11 голосов
/ 09 февраля 2015

Да, вы можете зарегистрировать приемник для изменения громкости (это своего рода хак, но работает), мне удалось сделать это следующим образом (без использования 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");       
        }
    }
}

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

8 голосов
/ 20 июля 2017

Исходя из * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}}}}}}}} * * * * * * * * * * * * * *В классе 1009 * мы видим, насколько просто прослушивать изменения громкости с помощью нашего пользовательского 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);
}

Надеюсь, это все еще полезно для кого-то!:)

7 голосов
/ 18 мая 2016

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

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;
    }
}
2 голосов
/ 01 декабря 2014

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

getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);

и поставить

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

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

2 голосов
/ 12 июля 2013

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

1 голос
/ 01 июня 2018
  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)
            }
        }
0 голосов
/ 16 декабря 2018

100% работает во всех случаях

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