Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

How to Disable High Volume Warning Message on Android

2.75/5 (3 votes)
15 Jun 2020CPOL3 min read 18.9K  
Two separate solutions: for devices with no root and for the rooted devices
This article describes why and when this dialog appears, and how to get rid of it.

Introduction

Sometimes, when you are using headphones with the Android device, the media volume may suddenly drop down and you can’t turn the volume back. To do that, you have to unlock the device and accept the warning:

The time when the dialog shows up is unpredictable: it may appear when you are driving the car/bicycle, or your hands are dirty/wet, etc. Of course, listening to loud music through the headphones may damage the hearing. But the device could not recognize what is connected: headphones or speakers. And in case of speakers, this message is meaningless.

Why It Shows Up

There are WHO-ETU standards for the listening systems. Their use is mandatory in the countries of the European Union and some other. The standards describe sound allowance for people depending on the audio volume and the listening time.

How It's Implemented in Android

Depending on the mcc (mobile country code), the warning can be enabled or disabled. It’s defined by the resource R.bool.config_safe_media_volume_enabled. If warning is enabled, then the system counts the “unsafe listening” time and shows the warning when it reaches 20 hours.
Listening is considered “unsafe” when the volume level is greater than 85 dB and headphones are connected. The cumulative “unsafe listening” time is stored in Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS and is updated every minute.
The safe listening system logic is implemented in AudioService.java.

Workaround for Rooted Devices

Set audio.safemedia.bypass=true in file system/build.properties:

Why it should work?
Let’s look at some fields in AudioService.java:

Java
// mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
// It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
// or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
// SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, 
// it can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
// (when user opts out).
private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;    // unconfirmed
private Integer mSafeMediaVolumeState;

The field mSafeMediaVolumeState keeps the current safe listening state:

  • DISABLED: Safe listening is disabled (volume level is not controlled)
  • ACTIVE: Safe listening is enabled, “unsafe listening” time has reached 20 hours, and user must confirm the dialog to be able to raise the volume up
  • INACTIVE: Safe listening is enabled, “unsafe listening” time has not reached 20 hours yet

We need mSafeMediaVolumeState to be assigned to DISABLED.
The initial value is assigned here:

Java
private void onConfigureSafeVolume(boolean force, String caller) {
   ...
   boolean safeMediaVolumeEnabled =
           SystemProperties.getBoolean("audio.safemedia.force", false)
                   || mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_safe_media_volume_enabled);

   boolean safeMediaVolumeBypass =
           SystemProperties.getBoolean("audio.safemedia.bypass", false);

   int persistedState;
   if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
       persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
       /* Omitted code. Here mSafeMediaVolumeState is assigned to ACTIVE, or INACTIVE */
...
   } else {
       persistedState = SAFE_MEDIA_VOLUME_DISABLED;
       mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
   }

It can be assigned to DISABLED in two cases: when R.bool.config_safe_media_volume_enabled=true (we can’t change it) or when audio.safemedia.bypass = true (we can change it with root privileges).

Workaround With No Root

The solution is to monitor the value of Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS and to not allow it to exceed 20 hours. The value should be reset when it gets close to the threshold.

How to Read the Current Value

Java
int unsafeMs = Settings.Secure.getInt(contentResolver, "unsafe_volume_music_active_ms")

The same using adb:

BAT
adb shell settings get secure unsafe_volume_music_active_ms

How to Update the Value

Firstly, grant the permissions to change the Secure Settings:

BAT
adb shell pm grant com.example.app android.permission.WRITE_SECURE_SETTINGS

It can be done because this permission has protectionLevel="signature|privileged|development",

Then call:

Java
Settings.Secure.putInt(contentResolver, "unsafe_volume_music_active_ms"
, 1)

It has to be 1, because 0 value is associated with ACTIVE state.

The same thing using adb:

BAT
adb shell settings put secure unsafe_volume_music_active_ms 1

After the value update, we need to ask the AudioService to read and use it. According to the source code, the only way to do that is to restart it. Audio service is a system service, so to restart it, the device must be rebooted (alternatively user can re-login).

In order to make this solution easier to use, I wrote code for a small app which periodically checks the Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS value and reminds to reboot the device.

Of course, it takes time to reboot or re-login, but this solution does not require root privileges.

History

  • 15th June, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)