Disabling Volume Indicator and Power ButtonsGo to Peripheral Settings > Hardware/software buttons. Disable Volume button – This option disables the user from changing the volume of the device.
It is possible. Use code below (for newer Android versions, especially Marshmallow, see bottom of the answer):
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("Ściszył!"); // volume decreased.
previousVolume=currentVolume;
}
else if(delta<0)
{
Logger.d("Zrobił głośniej!"); // volume increased.
previousVolume=currentVolume;
}
}
}
Then in your service onCreate register it with:
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
Then unregister in onDestroy:
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
Note that this example judges by change of media volume, if you want to use other volume, change it!
UPDATE:
Above method supposedly doesn't work on Marshmallow, BUT there's much better way now since MediaSession was introduced! So first you have to migrate your code to MediaController/MediaSession pattern and then use this code:
private VolumeProviderCompat myVolumeProvider = null;
myVolumeProvider = new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
@Override
public void onAdjustVolume(int direction) {
// <0 volume down
// >0 volume up
}
};
mSession.setPlaybackToRemote(myVolumeProvider);
Somehow volume button presses are detected even with screen off (just be sure to register proper media button intent receiver if applicable for your platform!)
UPDATE 2 since GalDude requested some more info on getting media MediaSession/MediaController. Sorry, but since I stopped using Java it will be in Kotlin:
lateinit var mediaSession: MediaSessionCompat // you have to initialize it in your onCreate method
val kontroler: MediaControllerCompat
get() = mediaSession.controller // in Java it's just getController() on mediaSession
// in your onCreate/start method:
mediaSession = MediaSessionCompat(this, "YourPlayerName", receiver, null)
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
mediaSession.isActive = true
if (ratingIsWorking) // note: rating crashes on some machines you have to check it!
mediaSession.setRatingType(RatingCompat.RATING_5_STARS)
mediaSession.setCallback(object : MediaSessionCompat.Callback() {
...
// here you have to implement what happens with your player when play/pause/stop/ffw etc. is requested - see exaples elsewhere
})
// onDestroy/exit method:
mediaSession.isActive = false
mediaSession.release()
The AOSP Music app has a Service (MediaPlaybackService) that responds to volume key events by registering a BroadcastReceiver (MediaButtonIntentReceiver).
Here's the code snippet where it registers the receiver:
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
ComponentName rec = new ComponentName(getPackageName(),
MediaButtonIntentReceiver.class.getName());
mAudioManager.registerMediaButtonEventReceiver(rec);
Also, don't forget about manifest:
<receiver android:name="com.android.music.MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
This works even if the Music app is not in the foreground. Isn't that what you want?
I was able to make it work on android 5+ devices using MediaSession
. However,ContentObserver
suggested by @ssuukk didn't work for me on both 4.4 and 7.0 devices (at least on ROMs that I've been testing on).
Here is a full example which works on android 5+.
Service:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.media.VolumeProviderCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
public class PlayerService extends Service {
private MediaSessionCompat mediaSession;
@Override
public void onCreate() {
super.onCreate();
mediaSession = new MediaSessionCompat(this, "PlayerService");
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 0) //you simulate a player which plays something.
.build());
//this will only work on Lollipop and up, see https://code.google.com/p/android/issues/detail?id=224134
VolumeProviderCompat myVolumeProvider =
new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, /*max volume*/100, /*initial volume level*/50) {
@Override
public void onAdjustVolume(int direction) {
/*
-1 -- volume down
1 -- volume up
0 -- volume button released
*/
}
};
mediaSession.setPlaybackToRemote(myVolumeProvider);
mediaSession.setActive(true);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
mediaSession.release();
}
}
In AndroidManifest.xml
:
<application ...>
...
<service android:name=".PlayerService"/>
</application>
In your activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
startService(new Intent(this, PlayerService.class));
}
There are several things to be aware of:
Settings->Applications
, find the app and force stop it to get volume buttons back.Unfortunately, this is another area of Android where there are like five different ways to "solve the problem", but most of them don't work very well. For my own sanity, I'll attempt to list all the different approaches below.
MediaSession
(from Service)Answer by Denis Kniazhev: https://stackoverflow.com/a/43304591/2441655
Drawbacks:
1. Requires Android SDK 21+ (Android 9+).
android.media.VOLUME_CHANGED_ACTION
(from Service)Answer by Nikhil: https://stackoverflow.com/a/44040282/2441655
Drawbacks:
1. Not an official part of the SDK: https://stackoverflow.com/a/8974510/2441655
2. Ignores first-press of volume-key (since it only shows the volume-bar).
3. Ignores volume-up key when at 100%, and volume-down key when at 0%.
ContentObserver
(from Service)Answer by ssuukk: https://stackoverflow.com/a/15292255/2441655 (first part)
Drawbacks:
1. Doesn't work in newer versions of Android: comment by dsemi
2. Ignores first-press of volume-key (since it only shows the volume-bar).
3. Ignores volume-up key when at 100%, and volume-down key when at 0%.
AudioManager.registerMediaButtonEventReceiver
(from Service)Answer by Joe: https://stackoverflow.com/a/11510564/2441655
Drawbacks:
1. Doesn't work on most roms: comment by elgui
onKeyDown
(from Activity)Answer by dipali: https://stackoverflow.com/a/21086563/2441655
Drawbacks:
1. Doesn't work if screen is off, in different app, etc.
dispatchKeyEvent
(from Activity)Answer by Maurice Gavin: https://stackoverflow.com/a/11462962/2441655
Drawbacks:
1. Doesn't work if screen is off, in different app, etc.
The solution I'm currently using is #1, because:
Let me know if you find any others -- or if you've found more drawbacks to some of them!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With