Reputation: 1819
Some Android apps generate a notification when the device's volume changes and some lock the volume. For the life of me, I cannot find out how that's done. Please, can someone help me by providing an example?
Upvotes: 5
Views: 12450
Reputation: 161
Actually there is one way you can do in service by using Content Observer. It works like a broadcast receiver, listen to the event of changing content such as volume, contacts, call log...
Using the following code in your service
public class VolumeService extends Service{
AudioManager mAudioManager;
Handler mHandler;
private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
if (mAudioManager != null) {
final int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
System.out.println("Volume: " + volume);
}
}
};
@Override
public void onCreate() {
super.onCreate();
System.out.println("Volume Service started");
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
//As of API 23, this approach ostensibly no longer works:
//Uri uri = Settings.System.getUriFor(Settings.System.VOLUME_SETTINGS[AudioManager.STREAM_RING]);
Uri uri = Settings.System.CONTENT_URI; //<-- This approach seems to be stable across versions, although will theoretically trigger onChange() during more types of system changes.
getContentResolver().registerContentObserver(uri, true, mVolumeObserver);
System.out.println("Volume listener registered.");
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("Volume service ended.");
getContentResolver().unregisterContentObserver(mVolumeObserver);
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Don't forget to declare it in the Android Manifest.xml
<service android:name=".service.VolumeService" >
Upvotes: 8
Reputation: 753
You can capture volume/hardware key events by using accessibility service.
How to capture key events inside a service?
Upvotes: 1
Reputation: 47069
This is one way to do it, you could just fix to a set volume instead of changing. My goal was to adjust system volume Service.
Also, avoid doing this only when needed.
public class VolumeKeyController {
private MediaSessionCompat mMediaSession;
private final Context mContext;
public VolumeKeyController(Context context) {
mContext = context;
}
private void createMediaSession() {
mMediaSession = new MediaSessionCompat(mContext, KeyUtil.log);
mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mMediaSession.setPlaybackState(new Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
.build());
mMediaSession.setPlaybackToRemote(getVolumeProvider());
mMediaSession.setActive(true);
}
private VolumeProviderCompat getVolumeProvider() {
final AudioManager audio = mContext.getSystemService(Context.AUDIO_SERVICE);
int STREAM_TYPE = AudioManager.STREAM_MUSIC;
int currentVolume = audio.getStreamVolume(STREAM_TYPE);
int maxVolume = audio.getStreamMaxVolume(STREAM_TYPE);
final int VOLUME_UP = 1;
final int VOLUME_DOWN = -1;
return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
@Override
public void onAdjustVolume(int direction) {
// Up = 1, Down = -1, Release = 0
// Replace with your action, if you don't want to adjust system volume
if (direction == VOLUME_UP) {
audio.adjustStreamVolume(STREAM_TYPE,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
}
else if (direction == VOLUME_DOWN) {
audio.adjustStreamVolume(STREAM_TYPE,
AudioManager.ADJUST_LOWER, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
}
setCurrentVolume(audio.getStreamVolume(STREAM_TYPE));
}
};
}
// Call when control needed, add a call to constructor if needed immediately
public void setActive(boolean active) {
if (mMediaSession != null) {
mMediaSession.setActive(active);
return;
}
createMediaSession();
}
// Call from Service's onDestroy method
public void destroy() {
if (mMediaSession != null) {
mMediaSession.release();
}
}
}
Upvotes: 0
Reputation: 14974
There is no Broadcast Action to detect volume changes, but you could maybe every second or two check what the volume is with getStreamVolume
and if you need to lock it at a specific volume, every second or two use: setStreamVolume
Check http://developer.android.com/reference/android/media/AudioManager.htm for more info.
You could use the AlarmManager class or a handler to check the volume every second or so.
If it's an activity, you can override onKeyDown
to detect key presses. See http://developer.android.com/reference/android/view/View.html
Upvotes: 5