ユーザーが呼び出し音の音量やバイブレーションの設定を変更するたびに更新する必要がある小さなウィジェットをプログラミングしています。
キャプチャAndroid.media.VIBRATE_SETTING_CHANGED
バイブレーション設定では問題なく動作しますが、呼び出し音の音量が変更されたときに通知を受け取る方法が見つかりませんでした。これらのキーを使用せずにボリュームを変更するためのオプション。
このために定義されたブロードキャストアクションがあるか、それを作成する方法、またはそれなしで問題を解決する方法があるかを知っていますか?
ブロードキャストアクションはありませんが、設定が変更されたときに通知を受けるためにコンテンツオブザーバーを接続できます。ストリームのボリュームはこれらの設定の一部です。 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();
}
}
そして、ある時点で必ずコンテンツオブザーバの登録を解除してください。
Nathanのコード は機能しますが、システム設定の変更ごとに2つの通知を提供します。それを回避するには、次を使用します
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");
}
}
}
それが役に立てば幸い!
Nathan's 、 adi's 、および swooby's code に基づいて、いくつかのマイナーな改良を加えた完全な実例を作成しました。
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);
}
それがまだ誰かに役立つことを願っています! :)
Nathanとadiのコードは機能しますが、クリーンアップして自己完結させることができます。
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 );
今は動作します。私の懸念は、変更時に音量ダイアログを非表示にする方法です。こちらをご覧ください image 。
その唯一の呼び出し音モードが変更された場合、アクションとして「Android.media.RINGER_MODE_CHANGED
」を指定してブロードキャストレシーバーを使用できます。簡単に実装できます
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)
}
}
すべての場合に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);
}