2011-08-01 6 views
42

Sto programmando un piccolo widget che deve essere aggiornato ogni volta che l'utente cambia il volume della suoneria o le impostazioni di vibrazione.Esiste un'azione di trasmissione per le modifiche al volume?

Cattura android.media.VIBRATE_SETTING_CHANGED funziona correttamente per le impostazioni di vibrazione, ma non ho trovato alcun modo di ottenere una notifica quando il volume della suoneria cambia e anche se potrei provare a catturare quando l'utente preme il volume su/volume giù tasti fisici, ci sono molte altre opzioni per cambiare il volume senza usare questi tasti.

Sai se è stata definita un'azione di trasmissione per questo o per qualsiasi altro modo di crearne uno o per risolvere il problema senza di esso?

risposta

63

Non c'è alcuna azione di trasmissione, ma ho trovato che è possibile collegare un osservatore di contenuto per ricevere una notifica quando le impostazioni cambiano, il volume degli stream è alcune di quelle impostazioni. Registrati per l'android.provider.Settings.System.CONTENT_URI per essere informato di tutte le modifiche delle impostazioni:

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

L'osservatore contenuto potrebbe essere simile a questo:

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

ed essere sicuri di annullare la registrazione del contenuto osservatore ad un certo punto.

+0

Grazie per la risposta, è un po 'estremo per quello che sto cercando di fare, ma sembra davvero l'opzione più vicina ... – LuTHieR

+1

@NathanTotura: I tasti del volume verranno rilevati quando lo schermo è spento? O la soluzione funziona solo nel caso in cui lo schermo è acceso? – Basher51

+0

I tasti del volume vengono rilevati anche utilizzando questo metodo quando lo schermo è spento. Almeno per AudioManager.STREAM_MUSIC, non ho testato per altri tipi di stream, ma presumo che si comportino allo stesso modo. – Waboodoo

56

Nathan's code funziona ma fornisce due notifiche per ogni impostazione del sistema di modifica. Per evitare che, utilizzare il seguente

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

Poi, nel vostro servizio onCreate registrarlo con:

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

Poi unregister nella OnDestroy:

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

Poiché Content_URI è l'URI generico, sto ricevendo la richiamata di onChange più volte. Voglio solo monitorare il cambiamento nel volume della suoneria. Provato con diversi URI per Ringtone ma nessuno di loro funziona. Qualcuno può aiutare? – Prashant

2

Se il suo unico cambiamento modalità suoneria è possibile utilizzare il ricevitore Brodcast con "android.media.RINGER_MODE_CHANGED" come azione. Sarà facile da implementare

2

Ciao ho provato il codice sopra e non ha funzionato per me. Ma quando ho cercato di aggiungere questa riga

getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); 

e mettere

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

ora funziona. La mia preoccupazione è come nascondere la finestra di dialogo del volume onchange. Vedi questo image.

8

Sì, è possibile registrare un ricevitore per un cambiamento di volume (questo è una specie di hack, ma funziona), sono riuscito a fare in questo modo (non comporta un ContentObserver): Nel file XML manifest:

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

speranza che aiuta!

+0

ha funzionato per me. Grazie. –

+0

Stai attento che questo non è supportato e può smettere di funzionare nelle versioni future: http://stackoverflow.com/a/8974510/383761 –

+0

Interrompe l'invio di callback sul ricevitore se il volume raggiunge un limite (ad esempio volume alto o muto). Ciò accade in alcuni dispositivi LG – Vasilisfoo

7

codice di Nathan e adi di opere, ma può essere ripulito e autosufficiente a:

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

Perché il downvote senza commenti? Come si suppone qualcuno che impari perché qualcosa è stato downvoted? – swooby

8

base in Nathan's, adi's e swooby's code ho creato un esempio di lavoro completo con alcuni piccoli miglioramenti.

Guardando alla classe AudioFragment possiamo vedere quanto sia facile è quello di ascoltare per il volume cambia con il nostro costume 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); 
} 

Spero che sia ancora utile per qualcuno! :)