diff options
| author | 2023-08-17 15:16:16 +0000 | |
|---|---|---|
| committer | 2023-08-17 15:16:16 +0000 | |
| commit | 2dcffbe76bae86445fb93e7b7e8ca026023cd55f (patch) | |
| tree | 0b8dd730aaaecf599a32f346551160172cd86b4d | |
| parent | 005d9699db3c36282266c1aaae605fb4bdb7f1b8 (diff) | |
| parent | 42965041158dce9da5e9f577870d25de692ccc43 (diff) | |
Merge "CSD: Implement new logic for enabling CSD" into udc-qpr-dev
7 files changed, 171 insertions, 36 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1235b787c8e2..99b080095afb 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9975,6 +9975,13 @@ public final class Settings { public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory"; /** + * Stores a boolean that defines whether the CSD as a feature is enabled or not. + * @hide + */ + public static final String AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED = + "audio_safe_csd_as_a_feature_enabled"; + + /** * Indicates whether notification display on the lock screen is enabled. * <p> * Type: int (0 for false, 1 for true) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d86d53fd8059..55b251777f0c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3013,14 +3013,15 @@ on the headphone/microphone jack. When false use the older uevent framework. --> <bool name="config_useDevInputEventForAudioJack">false</bool> - <!-- Whether safe headphone volume is enabled or not (country specific). --> + <!-- Whether safe headphone hearing is enforced by any regulation (e.g. + EN50332-3, EN50332-2) or not (country specific). --> <bool name="config_safe_media_volume_enabled">true</bool> - <!-- Whether safe headphone sound dosage warning is enabled or not - (country specific). This value should only be overlaid to true - when a vendor supports offload and has the HAL sound dose - interfaces implemented. Otherwise, this can lead to a compliance - issue with the safe hearing standards EN50332-3 and IEC62368-1. + <!-- Whether safe headphone sound dosage warning is enabled or not. + This value should only be overlaid to true when a vendor supports + offload and has the HAL sound dose interfaces implemented. + Otherwise, this can lead to a compliance issue with the safe + hearing standards EN50332-3 and IEC62368-1. --> <bool name="config_safe_sound_dosage_enabled">false</bool> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e8c9d0dbd884..c3087bc1c0d2 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -6915,7 +6915,10 @@ public class AudioManager { /** * @hide - * Returns whether CSD is enabled and supported by the HAL on this device. + * Returns whether CSD is enabled and supported by the current active audio module HAL. + * This method will return {@code false) for setups in which CSD as a feature is available + * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see + * {@link AudioManager#isCsdAsAFeatureEnabled()}). */ @TestApi @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) @@ -6929,6 +6932,49 @@ public class AudioManager { /** * @hide + * Returns whether CSD as a feature can be manipulated by a client. This method + * returns {@code true} in countries where there isn't a safe hearing regulation + * enforced. + */ + @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public boolean isCsdAsAFeatureAvailable() { + try { + return getService().isCsdAsAFeatureAvailable(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Returns {@code true} if the client has enabled CSD. This function should only + * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. + */ + @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public boolean isCsdAsAFeatureEnabled() { + try { + return getService().isCsdAsAFeatureEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + * Enables/disables the CSD feature. This function should only be called if + * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. + */ + @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public void setCsdAsAFeatureEnabled(boolean csdToggleValue) { + try { + getService().setCsdAsAFeatureEnabled(csdToggleValue); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide * Describes an audio device that has not been categorized with a specific * audio type. */ diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 180c7fde6a15..9d62e37ec97b 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -323,6 +323,15 @@ interface IAudioService { boolean isCsdEnabled(); @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED") + boolean isCsdAsAFeatureAvailable(); + + @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED") + boolean isCsdAsAFeatureEnabled(); + + @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED") + oneway void setCsdAsAFeatureEnabled(boolean csdToggleValue); + + @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED") oneway void setBluetoothAudioDeviceCategory(in String address, boolean isBle, int deviceType); @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED") diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 9b8e47300f9b..91c72b543cc4 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -703,7 +703,8 @@ public class SettingsBackupTest { Settings.Secure.ASSIST_SCREENSHOT_ENABLED, Settings.Secure.ASSIST_STRUCTURE_ENABLED, Settings.Secure.ATTENTIVE_TIMEOUT, - Settings.Secure.AUDIO_DEVICE_INVENTORY, // setting not controllable by user + Settings.Secure.AUDIO_DEVICE_INVENTORY, // not controllable by user + Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED, // not controllable by user Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6a73c2b85aaa..ceb96efd2e72 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -10691,6 +10691,27 @@ public class AudioService extends IAudioService.Stub @Override @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public boolean isCsdAsAFeatureAvailable() { + super.isCsdAsAFeatureAvailable_enforcePermission(); + return mSoundDoseHelper.isCsdAsAFeatureAvailable(); + } + + @Override + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public boolean isCsdAsAFeatureEnabled() { + super.isCsdAsAFeatureEnabled_enforcePermission(); + return mSoundDoseHelper.isCsdAsAFeatureEnabled(); + } + + @Override + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) + public void setCsdAsAFeatureEnabled(boolean csdToggleValue) { + super.setCsdAsAFeatureEnabled_enforcePermission(); + mSoundDoseHelper.setCsdAsAFeatureEnabled(csdToggleValue); + } + + @Override + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void setBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle, @AudioDeviceCategory int btAudioDeviceCategory) { super.setBluetoothAudioDeviceCategory_enforcePermission(); diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index 851c5c3cb73c..5ebc1c055b50 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -37,13 +37,11 @@ import android.media.ISoundDose; import android.media.ISoundDoseCallback; import android.media.SoundDoseRecord; import android.os.Binder; -import android.os.HandlerExecutor; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -143,8 +141,6 @@ public class SoundDoseHelper { private static final int SAFE_MEDIA_VOLUME_UNINITIALIZED = -1; - private static final String FEATURE_FLAG_ENABLE_CSD = "enable_csd"; - private final EventLogger mLogger = new EventLogger(AudioService.LOG_NB_EVENTS_SOUND_DOSE, "CSD updates"); @@ -193,7 +189,15 @@ public class SoundDoseHelper { private final AtomicBoolean mEnableCsd = new AtomicBoolean(false); - private ArrayList<ISoundDose.AudioDeviceCategory> mCachedAudioDeviceCategories = + private final Object mCsdAsAFeatureLock = new Object(); + + @GuardedBy("mCsdAsAFeatureLock") + private boolean mIsCsdAsAFeatureAvailable = false; + + @GuardedBy("mCsdAsAFeatureLock") + private boolean mIsCsdAsAFeatureEnabled = false; + + private final ArrayList<ISoundDose.AudioDeviceCategory> mCachedAudioDeviceCategories = new ArrayList<>(); private final Object mCsdStateLock = new Object(); @@ -315,10 +319,6 @@ public class SoundDoseHelper { mAlarmManager = (AlarmManager) mContext.getSystemService( Context.ALARM_SERVICE); - - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_MEDIA, - new HandlerExecutor(mAudioHandler), - p -> updateCsdEnabled("onPropertiesChanged")); } void initSafeVolumes() { @@ -494,6 +494,38 @@ public class SoundDoseHelper { return false; } + boolean isCsdAsAFeatureAvailable() { + synchronized (mCsdAsAFeatureLock) { + return mIsCsdAsAFeatureAvailable; + } + } + + boolean isCsdAsAFeatureEnabled() { + synchronized (mCsdAsAFeatureLock) { + return mIsCsdAsAFeatureEnabled; + } + } + + void setCsdAsAFeatureEnabled(boolean csdAsAFeatureEnabled) { + boolean doUpdate; + synchronized (mCsdAsAFeatureLock) { + doUpdate = mIsCsdAsAFeatureEnabled != csdAsAFeatureEnabled && mIsCsdAsAFeatureAvailable; + mIsCsdAsAFeatureEnabled = csdAsAFeatureEnabled; + final long callingIdentity = Binder.clearCallingIdentity(); + try { + mSettings.putSecureIntForUser(mAudioService.getContentResolver(), + Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED, + mIsCsdAsAFeatureEnabled ? 1 : 0, UserHandle.USER_CURRENT); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + if (doUpdate) { + updateCsdEnabled("setCsdAsAFeatureEnabled"); + } + } + void setAudioDeviceCategory(String address, int internalAudioType, boolean isHeadphone) { if (!mEnableCsd.get()) { return; @@ -864,6 +896,13 @@ public class SoundDoseHelper { Log.e(TAG, "Exception while forcing the internal MEL computation", e); } + synchronized (mCsdAsAFeatureLock) { + mIsCsdAsAFeatureEnabled = mSettings.getSecureIntForUser( + mAudioService.getContentResolver(), + Settings.Secure.AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED, 0, + UserHandle.USER_CURRENT) != 0; + } + synchronized (mCsdStateLock) { if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) { mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L; @@ -908,18 +947,23 @@ public class SoundDoseHelper { @GuardedBy("mSafeMediaVolumeStateLock") private void updateSafeMediaVolume_l(String caller) { - boolean safeMediaVolumeEnabled = - SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE, false) - || (mContext.getResources().getBoolean( - com.android.internal.R.bool.config_safe_media_volume_enabled) - && !mEnableCsd.get()); boolean safeMediaVolumeBypass = - SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false); + SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false) + || mEnableCsd.get(); + boolean safeMediaVolumeForce = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE, + false); + // we are using the MCC overlaid legacy flag used for the safe volume enablement + // to determine whether the MCC enforces any safe hearing standard. + boolean mccEnforcedSafeMediaVolume = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_safe_media_volume_enabled); + + boolean safeVolumeEnabled = + (mccEnforcedSafeMediaVolume || safeMediaVolumeForce) && !safeMediaVolumeBypass; // The persisted state is either "disabled" or "active": this is the state applied // next time we boot and cannot be "inactive" int persistedState; - if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) { + if (safeVolumeEnabled) { persistedState = SAFE_MEDIA_VOLUME_ACTIVE; // The state can already be "inactive" here if the user has forced it before // the 30 seconds timeout for forced configuration. In this case we don't reset @@ -946,22 +990,28 @@ public class SoundDoseHelper { } private void updateCsdEnabled(String caller) { - boolean newEnableCsd = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE, - false); - if (!newEnableCsd) { - final String featureFlagEnableCsdValue = DeviceConfig.getProperty( - DeviceConfig.NAMESPACE_MEDIA, - FEATURE_FLAG_ENABLE_CSD); - if (featureFlagEnableCsdValue != null) { - newEnableCsd = Boolean.parseBoolean(featureFlagEnableCsdValue); + boolean csdForce = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_CSD_FORCE, false); + // we are using the MCC overlaid legacy flag used for the safe volume enablement + // to determine whether the MCC enforces any safe hearing standard. + boolean mccEnforcedSafeMedia = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_safe_media_volume_enabled); + boolean csdEnable = mContext.getResources().getBoolean( + R.bool.config_safe_sound_dosage_enabled); + boolean newEnabledCsd = (mccEnforcedSafeMedia && csdEnable) || csdForce; + + synchronized (mCsdAsAFeatureLock) { + if (!mccEnforcedSafeMedia && csdEnable) { + mIsCsdAsAFeatureAvailable = true; + newEnabledCsd = mIsCsdAsAFeatureEnabled || csdForce; + Log.v(TAG, caller + ": CSD as a feature is not enforced and enabled: " + + newEnabledCsd); } else { - newEnableCsd = mContext.getResources().getBoolean( - R.bool.config_safe_sound_dosage_enabled); + mIsCsdAsAFeatureAvailable = false; } } - if (mEnableCsd.compareAndSet(!newEnableCsd, newEnableCsd)) { - Log.i(TAG, caller + ": enable CSD " + newEnableCsd); + if (mEnableCsd.compareAndSet(!newEnabledCsd, newEnabledCsd)) { + Log.i(TAG, caller + ": enabled CSD " + newEnabledCsd); initCsd(); synchronized (mSafeMediaVolumeStateLock) { |