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.Manifest.permission.MODIFY_PHONE_STATE 22 import android.app.settings.SettingsEnums.ACTION_CALL_VOLUME 23 import android.content.Context 24 import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE 25 import android.media.AudioManager 26 import android.media.AudioManager.STREAM_BLUETOOTH_SCO 27 import android.media.AudioManager.STREAM_VOICE_CALL 28 import android.os.UserManager 29 import androidx.preference.Preference 30 import com.android.settings.R 31 import com.android.settings.contract.KEY_CALL_VOLUME 32 import com.android.settings.metrics.PreferenceActionMetricsProvider 33 import com.android.settings.restriction.PreferenceRestrictionMixin 34 import com.android.settingslib.datastore.KeyValueStore 35 import com.android.settingslib.datastore.NoOpKeyedObservable 36 import com.android.settingslib.datastore.Permissions 37 import com.android.settingslib.datastore.and 38 import com.android.settingslib.metadata.IntRangeValuePreference 39 import com.android.settingslib.metadata.PreferenceAvailabilityProvider 40 import com.android.settingslib.metadata.PreferenceIconProvider 41 import com.android.settingslib.metadata.PreferenceMetadata 42 import com.android.settingslib.metadata.ReadWritePermit 43 import com.android.settingslib.metadata.SensitivityLevel 44 import com.android.settingslib.preference.PreferenceBinding 45 46 // LINT.IfChange 47 open class CallVolumePreference : 48 IntRangeValuePreference, 49 PreferenceBinding, 50 PreferenceActionMetricsProvider, 51 PreferenceAvailabilityProvider, 52 PreferenceIconProvider, 53 PreferenceRestrictionMixin { 54 override val key: String 55 get() = KEY 56 57 override val title: Int 58 get() = R.string.call_volume_option_title 59 60 override val preferenceActionMetrics: Int 61 get() = ACTION_CALL_VOLUME 62 tagsnull63 override fun tags(context: Context) = arrayOf(KEY_CALL_VOLUME) 64 65 override fun getIcon(context: Context) = R.drawable.ic_local_phone_24_lib 66 67 override fun isAvailable(context: Context) = 68 context.resources.getBoolean(R.bool.config_show_call_volume) && 69 !createAudioHelper(context).isSingleVolume 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(getAudioStream(context)) as T 84 85 override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { 86 helper.setStreamVolume(getAudioStream(context), 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, MODIFY_PHONE_STATE) 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(getAudioStream(context)) 112 113 override fun getMaxValue(context: Context) = 114 createAudioHelper(context).getMaxVolume(getAudioStream(context)) 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).setStream(getAudioStream(preference.context)) 121 } 122 createAudioHelpernull123 open fun createAudioHelper(context: Context) = AudioHelper(context) 124 125 @Suppress("DEPRECATION") 126 fun getAudioStream(context: Context): Int { 127 val audioManager = context.getSystemService(AudioManager::class.java) 128 return when { 129 audioManager.isBluetoothScoOn() -> STREAM_BLUETOOTH_SCO 130 else -> STREAM_VOICE_CALL 131 } 132 } 133 134 companion object { 135 const val KEY = "call_volume" 136 } 137 } 138 // LINT.ThenChange(CallVolumePreferenceController.java) 139