1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification 18 19 import android.Manifest.permission.MODIFY_AUDIO_SETTINGS 20 import android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 21 import android.app.settings.SettingsEnums.ACTION_MEDIA_VOLUME 22 import android.content.Context 23 import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE 24 import android.media.AudioManager.STREAM_MUSIC 25 import android.os.UserManager 26 import androidx.preference.Preference 27 import com.android.settings.R 28 import com.android.settings.contract.KEY_MEDIA_VOLUME 29 import com.android.settings.metrics.PreferenceActionMetricsProvider 30 import com.android.settings.restriction.PreferenceRestrictionMixin 31 import com.android.settingslib.datastore.KeyValueStore 32 import com.android.settingslib.datastore.NoOpKeyedObservable 33 import com.android.settingslib.datastore.Permissions 34 import com.android.settingslib.datastore.and 35 import com.android.settingslib.metadata.IntRangeValuePreference 36 import com.android.settingslib.metadata.PreferenceAvailabilityProvider 37 import com.android.settingslib.metadata.PreferenceIconProvider 38 import com.android.settingslib.metadata.PreferenceMetadata 39 import com.android.settingslib.metadata.ReadWritePermit 40 import com.android.settingslib.metadata.SensitivityLevel 41 import com.android.settingslib.preference.PreferenceBinding 42 43 // LINT.IfChange 44 open class MediaVolumePreference : 45 IntRangeValuePreference, 46 PreferenceBinding, 47 PreferenceActionMetricsProvider, 48 PreferenceAvailabilityProvider, 49 PreferenceIconProvider, 50 PreferenceRestrictionMixin { 51 override val key: String 52 get() = KEY 53 54 override val title: Int 55 get() = R.string.media_volume_option_title 56 57 override val preferenceActionMetrics: Int 58 get() = ACTION_MEDIA_VOLUME 59 tagsnull60 override fun tags(context: Context) = arrayOf(KEY_MEDIA_VOLUME) 61 62 override fun getIcon(context: Context) = 63 when { 64 VolumeHelper.isMuted(context, STREAM_MUSIC) -> R.drawable.ic_media_stream_off 65 else -> R.drawable.ic_media_stream 66 } 67 isAvailablenull68 override fun isAvailable(context: Context) = 69 context.resources.getBoolean(R.bool.config_show_media_volume) 70 71 override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) 72 73 override val restrictionKeys 74 get() = arrayOf(UserManager.DISALLOW_ADJUST_VOLUME) 75 76 override fun storage(context: Context): KeyValueStore { 77 val helper = createAudioHelper(context) 78 return object : NoOpKeyedObservable<String>(), KeyValueStore { 79 override fun contains(key: String) = key == KEY 80 81 @Suppress("UNCHECKED_CAST") 82 override fun <T : Any> getValue(key: String, valueType: Class<T>) = 83 helper.getStreamVolume(STREAM_MUSIC) as T 84 85 override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { 86 helper.setStreamVolume(STREAM_MUSIC, value as Int) 87 } 88 } 89 } 90 getReadPermissionsnull91 override fun getReadPermissions(context: Context) = Permissions.EMPTY 92 93 override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = 94 ReadWritePermit.ALLOW 95 96 override fun getWritePermissions(context: Context): Permissions? { 97 var permissions = Permissions.allOf(MODIFY_AUDIO_SETTINGS) 98 if (context.packageManager.hasSystemFeature(FEATURE_AUTOMOTIVE)) { 99 permissions = permissions and MODIFY_AUDIO_SETTINGS_PRIVILEGED 100 } 101 return permissions 102 } 103 getWritePermitnull104 override fun getWritePermit(context: Context, value: Int?, callingPid: Int, callingUid: Int) = 105 ReadWritePermit.ALLOW 106 107 override val sensitivityLevel 108 get() = SensitivityLevel.NO_SENSITIVITY 109 110 override fun getMinValue(context: Context) = 111 createAudioHelper(context).getMinVolume(STREAM_MUSIC) 112 113 override fun getMaxValue(context: Context) = 114 createAudioHelper(context).getMaxVolume(STREAM_MUSIC) 115 116 override fun createWidget(context: Context) = VolumeSeekBarPreference(context) 117 118 override fun bind(preference: Preference, metadata: PreferenceMetadata) { 119 super.bind(preference, metadata) 120 (preference as VolumeSeekBarPreference).apply { 121 setStream(STREAM_MUSIC) 122 setMuteIcon(R.drawable.ic_media_stream_off) 123 setListener { updateContentDescription(this) } 124 } 125 } 126 createAudioHelpernull127 open fun createAudioHelper(context: Context) = AudioHelper(context) 128 129 private fun updateContentDescription(preference: VolumeSeekBarPreference) { 130 when { 131 preference.isMuted -> 132 preference.updateContentDescription( 133 preference.context.getString( 134 R.string.volume_content_description_silent_mode, 135 preference.title, 136 ) 137 ) 138 else -> preference.updateContentDescription(preference.title) 139 } 140 } 141 142 companion object { 143 const val KEY = "media_volume" 144 } 145 } 146 // LINT.ThenChange(MediaVolumePreferenceController.java) 147