1 /* 2 * Copyright 2020 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.server.hdmi; 18 19 import static android.hardware.hdmi.HdmiControlManager.CecSettingName; 20 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.StringDef; 25 import android.content.Context; 26 import android.content.SharedPreferences; 27 import android.hardware.hdmi.HdmiControlManager; 28 import android.os.Environment; 29 import android.os.SystemProperties; 30 import android.provider.Settings.Global; 31 import android.util.ArrayMap; 32 import android.util.Slog; 33 34 import com.android.internal.R; 35 import com.android.internal.annotations.GuardedBy; 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.internal.util.ConcurrentUtils; 38 39 import java.io.File; 40 import java.util.ArrayList; 41 import java.util.LinkedHashMap; 42 import java.util.List; 43 import java.util.Map.Entry; 44 import java.util.concurrent.Executor; 45 46 /** 47 * The {@link HdmiCecConfig} class is used for getting information about 48 * available HDMI CEC settings. 49 */ 50 public class HdmiCecConfig { 51 private static final String TAG = "HdmiCecConfig"; 52 53 private static final String ETC_DIR = "etc"; 54 private static final String CONFIG_FILE = "cec_config.xml"; 55 private static final String SHARED_PREFS_DIR = "shared_prefs"; 56 private static final String SHARED_PREFS_NAME = "cec_config.xml"; 57 58 private static final int STORAGE_SYSPROPS = 0; 59 private static final int STORAGE_GLOBAL_SETTINGS = 1; 60 private static final int STORAGE_SHARED_PREFS = 2; 61 62 @IntDef({ 63 STORAGE_SYSPROPS, 64 STORAGE_GLOBAL_SETTINGS, 65 STORAGE_SHARED_PREFS, 66 }) 67 private @interface Storage {} 68 69 private static final String VALUE_TYPE_STRING = "string"; 70 private static final String VALUE_TYPE_INT = "int"; 71 72 @StringDef({ 73 VALUE_TYPE_STRING, 74 VALUE_TYPE_INT, 75 }) 76 private @interface ValueType {} 77 78 @NonNull private final Context mContext; 79 @NonNull private final StorageAdapter mStorageAdapter; 80 81 private final Object mLock = new Object(); 82 83 @GuardedBy("mLock") 84 private final ArrayMap<Setting, ArrayMap<SettingChangeListener, Executor>> 85 mSettingChangeListeners = new ArrayMap<>(); 86 87 private LinkedHashMap<String, Setting> mSettings = new LinkedHashMap<>(); 88 89 /** 90 * Exception thrown when the CEC Configuration setup verification fails. 91 * This usually means a settings lacks default value or storage/storage key. 92 */ 93 public static class VerificationException extends RuntimeException { VerificationException(String message)94 public VerificationException(String message) { 95 super(message); 96 } 97 } 98 99 /** 100 * Listener used to get notifications when value of a setting changes. 101 */ 102 public interface SettingChangeListener { 103 /** 104 * Called when value of a setting changes. 105 * 106 * @param setting name of a CEC setting that changed 107 */ onChange(@onNull @ecSettingName String setting)108 void onChange(@NonNull @CecSettingName String setting); 109 } 110 111 /** 112 * Setting storage input/output helper class. 113 */ 114 public static class StorageAdapter { 115 @NonNull private final Context mContext; 116 @NonNull private final SharedPreferences mSharedPrefs; 117 StorageAdapter(@onNull Context context)118 StorageAdapter(@NonNull Context context) { 119 mContext = context; 120 // The package info in the context isn't initialized in the way it is for normal apps, 121 // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we 122 // build the path manually below using the same policy that appears in ContextImpl. 123 final Context deviceContext = mContext.createDeviceProtectedStorageContext(); 124 final File prefsFile = new File(new File(Environment.getDataSystemDirectory(), 125 SHARED_PREFS_DIR), SHARED_PREFS_NAME); 126 mSharedPrefs = deviceContext.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); 127 } 128 129 /** 130 * Read the value from a system property. 131 * Returns the given default value if the system property is not set. 132 */ retrieveSystemProperty(@onNull String storageKey, @NonNull String defaultValue)133 public String retrieveSystemProperty(@NonNull String storageKey, 134 @NonNull String defaultValue) { 135 return SystemProperties.get(storageKey, defaultValue); 136 } 137 138 /** 139 * Write the value to a system property. 140 */ storeSystemProperty(@onNull String storageKey, @NonNull String value)141 public void storeSystemProperty(@NonNull String storageKey, 142 @NonNull String value) { 143 SystemProperties.set(storageKey, value); 144 } 145 146 /** 147 * Read the value from a global setting. 148 * Returns the given default value if the system property is not set. 149 */ retrieveGlobalSetting(@onNull String storageKey, @NonNull String defaultValue)150 public String retrieveGlobalSetting(@NonNull String storageKey, 151 @NonNull String defaultValue) { 152 String value = Global.getString(mContext.getContentResolver(), storageKey); 153 return value != null ? value : defaultValue; 154 } 155 156 /** 157 * Write the value to a global setting. 158 */ storeGlobalSetting(@onNull String storageKey, @NonNull String value)159 public void storeGlobalSetting(@NonNull String storageKey, 160 @NonNull String value) { 161 Global.putString(mContext.getContentResolver(), storageKey, value); 162 } 163 164 /** 165 * Read the value from a shared preference. 166 * Returns the given default value if the preference is not set. 167 */ retrieveSharedPref(@onNull String storageKey, @NonNull String defaultValue)168 public String retrieveSharedPref(@NonNull String storageKey, 169 @NonNull String defaultValue) { 170 return mSharedPrefs.getString(storageKey, defaultValue); 171 } 172 173 /** 174 * Write the value to a shared preference. 175 */ storeSharedPref(@onNull String storageKey, @NonNull String value)176 public void storeSharedPref(@NonNull String storageKey, 177 @NonNull String value) { 178 mSharedPrefs.edit().putString(storageKey, value).apply(); 179 } 180 } 181 182 private class Value { 183 private final String mStringValue; 184 private final Integer mIntValue; 185 Value(@onNull String value)186 Value(@NonNull String value) { 187 mStringValue = value; 188 mIntValue = null; 189 } 190 Value(@onNull Integer value)191 Value(@NonNull Integer value) { 192 mStringValue = null; 193 mIntValue = value; 194 } 195 getStringValue()196 String getStringValue() { 197 return mStringValue; 198 } 199 getIntValue()200 Integer getIntValue() { 201 return mIntValue; 202 } 203 } 204 205 protected class Setting { 206 @NonNull private final Context mContext; 207 @NonNull private final @CecSettingName String mName; 208 private final boolean mUserConfigurable; 209 210 private Value mDefaultValue = null; 211 private List<Value> mAllowedValues = new ArrayList<>(); 212 Setting(@onNull Context context, @NonNull @CecSettingName String name, int userConfResId)213 Setting(@NonNull Context context, 214 @NonNull @CecSettingName String name, 215 int userConfResId) { 216 mContext = context; 217 mName = name; 218 mUserConfigurable = mContext.getResources().getBoolean(userConfResId); 219 } 220 getName()221 public @CecSettingName String getName() { 222 return mName; 223 } 224 getValueType()225 public @ValueType String getValueType() { 226 return getDefaultValue().getStringValue() != null 227 ? VALUE_TYPE_STRING 228 : VALUE_TYPE_INT; 229 } 230 getDefaultValue()231 public Value getDefaultValue() { 232 if (mDefaultValue == null) { 233 throw new VerificationException("Invalid CEC setup for '" 234 + this.getName() + "' setting. " 235 + "Setting has no default value."); 236 } 237 return mDefaultValue; 238 } 239 getUserConfigurable()240 public boolean getUserConfigurable() { 241 return mUserConfigurable; 242 } 243 registerValue(@onNull Value value, int allowedResId, int defaultResId)244 private void registerValue(@NonNull Value value, 245 int allowedResId, int defaultResId) { 246 if (mContext.getResources().getBoolean(allowedResId)) { 247 mAllowedValues.add(value); 248 if (mContext.getResources().getBoolean(defaultResId)) { 249 if (mDefaultValue != null) { 250 Slog.e(TAG, 251 "Failed to set '" + value + "' as a default for '" + this.getName() 252 + "': Setting already has a default ('" + mDefaultValue 253 + "')."); 254 return; 255 } 256 mDefaultValue = value; 257 } 258 } 259 } 260 registerValue(@onNull String value, int allowedResId, int defaultResId)261 public void registerValue(@NonNull String value, int allowedResId, 262 int defaultResId) { 263 registerValue(new Value(value), allowedResId, defaultResId); 264 } 265 registerValue(int value, int allowedResId, int defaultResId)266 public void registerValue(int value, int allowedResId, 267 int defaultResId) { 268 registerValue(new Value(value), allowedResId, defaultResId); 269 } 270 271 getAllowedValues()272 public List<Value> getAllowedValues() { 273 return mAllowedValues; 274 } 275 } 276 277 @VisibleForTesting HdmiCecConfig(@onNull Context context, @NonNull StorageAdapter storageAdapter)278 HdmiCecConfig(@NonNull Context context, 279 @NonNull StorageAdapter storageAdapter) { 280 mContext = context; 281 mStorageAdapter = storageAdapter; 282 283 // IMPORTANT: when adding a config value for a particular setting, register that value AFTER 284 // the existing values for that setting. That way, defaults set in the RRO are forward 285 // compatible even if the RRO doesn't include that new value yet 286 // (e.g. because it's ported from a previous release). 287 288 Setting hdmiCecEnabled = registerSetting( 289 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, 290 R.bool.config_cecHdmiCecEnabled_userConfigurable); 291 hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED, 292 R.bool.config_cecHdmiCecControlEnabled_allowed, 293 R.bool.config_cecHdmiCecControlEnabled_default); 294 hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED, 295 R.bool.config_cecHdmiCecControlDisabled_allowed, 296 R.bool.config_cecHdmiCecControlDisabled_default); 297 298 Setting hdmiCecVersion = registerSetting( 299 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, 300 R.bool.config_cecHdmiCecVersion_userConfigurable); 301 hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_1_4_B, 302 R.bool.config_cecHdmiCecVersion14b_allowed, 303 R.bool.config_cecHdmiCecVersion14b_default); 304 hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_2_0, 305 R.bool.config_cecHdmiCecVersion20_allowed, 306 R.bool.config_cecHdmiCecVersion20_default); 307 308 Setting routingControlControl = registerSetting( 309 HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL, 310 R.bool.config_cecRoutingControl_userConfigurable); 311 routingControlControl.registerValue(HdmiControlManager.ROUTING_CONTROL_ENABLED, 312 R.bool.config_cecRoutingControlEnabled_allowed, 313 R.bool.config_cecRoutingControlEnabled_default); 314 routingControlControl.registerValue(HdmiControlManager.ROUTING_CONTROL_DISABLED, 315 R.bool.config_cecRoutingControlDisabled_allowed, 316 R.bool.config_cecRoutingControlDisabled_default); 317 318 Setting powerControlMode = registerSetting( 319 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, 320 R.bool.config_cecPowerControlMode_userConfigurable); 321 powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV, 322 R.bool.config_cecPowerControlModeTv_allowed, 323 R.bool.config_cecPowerControlModeTv_default); 324 powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST, 325 R.bool.config_cecPowerControlModeBroadcast_allowed, 326 R.bool.config_cecPowerControlModeBroadcast_default); 327 powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_NONE, 328 R.bool.config_cecPowerControlModeNone_allowed, 329 R.bool.config_cecPowerControlModeNone_default); 330 powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM, 331 R.bool.config_cecPowerControlModeTvAndAudioSystem_allowed, 332 R.bool.config_cecPowerControlModeTvAndAudioSystem_default); 333 334 Setting powerStateChangeOnActiveSourceLost = registerSetting( 335 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, 336 R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable); 337 powerStateChangeOnActiveSourceLost.registerValue( 338 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE, 339 R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed, 340 R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default); 341 powerStateChangeOnActiveSourceLost.registerValue( 342 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW, 343 R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed, 344 R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default); 345 346 Setting systemAudioControl = registerSetting( 347 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL, 348 R.bool.config_cecSystemAudioControl_userConfigurable); 349 systemAudioControl.registerValue(HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED, 350 R.bool.config_cecSystemAudioControlEnabled_allowed, 351 R.bool.config_cecSystemAudioControlEnabled_default); 352 systemAudioControl.registerValue(HdmiControlManager.SYSTEM_AUDIO_CONTROL_DISABLED, 353 R.bool.config_cecSystemAudioControlDisabled_allowed, 354 R.bool.config_cecSystemAudioControlDisabled_default); 355 356 Setting systemAudioModeMuting = registerSetting( 357 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, 358 R.bool.config_cecSystemAudioModeMuting_userConfigurable); 359 systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED, 360 R.bool.config_cecSystemAudioModeMutingEnabled_allowed, 361 R.bool.config_cecSystemAudioModeMutingEnabled_default); 362 systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED, 363 R.bool.config_cecSystemAudioModeMutingDisabled_allowed, 364 R.bool.config_cecSystemAudioModeMutingDisabled_default); 365 366 Setting volumeControlMode = registerSetting( 367 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, 368 R.bool.config_cecVolumeControlMode_userConfigurable); 369 volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_ENABLED, 370 R.bool.config_cecVolumeControlModeEnabled_allowed, 371 R.bool.config_cecVolumeControlModeEnabled_default); 372 volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_DISABLED, 373 R.bool.config_cecVolumeControlModeDisabled_allowed, 374 R.bool.config_cecVolumeControlModeDisabled_default); 375 376 Setting tvWakeOnOneTouchPlay = registerSetting( 377 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, 378 R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable); 379 tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED, 380 R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed, 381 R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default); 382 tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED, 383 R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed, 384 R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default); 385 386 Setting tvSendStandbyOnSleep = registerSetting( 387 HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, 388 R.bool.config_cecTvSendStandbyOnSleep_userConfigurable); 389 tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED, 390 R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed, 391 R.bool.config_cecTvSendStandbyOnSleepEnabled_default); 392 tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED, 393 R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed, 394 R.bool.config_cecTvSendStandbyOnSleepDisabled_default); 395 396 Setting setMenuLanguage = registerSetting( 397 HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE, 398 R.bool.config_cecSetMenuLanguage_userConfigurable); 399 setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_ENABLED, 400 R.bool.config_cecSetMenuLanguageEnabled_allowed, 401 R.bool.config_cecSetMenuLanguageEnabled_default); 402 setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_DISABLED, 403 R.bool.config_cecSetMenuLanguageDisabled_allowed, 404 R.bool.config_cecSetMenuLanguageDisabled_default); 405 406 Setting rcProfileTv = registerSetting( 407 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV, 408 R.bool.config_cecRcProfileTv_userConfigurable); 409 rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_NONE, 410 R.bool.config_cecRcProfileTvNone_allowed, 411 R.bool.config_cecRcProfileTvNone_default); 412 rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_ONE, 413 R.bool.config_cecRcProfileTvOne_allowed, 414 R.bool.config_cecRcProfileTvOne_default); 415 rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_TWO, 416 R.bool.config_cecRcProfileTvTwo_allowed, 417 R.bool.config_cecRcProfileTvTwo_default); 418 rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_THREE, 419 R.bool.config_cecRcProfileTvThree_allowed, 420 R.bool.config_cecRcProfileTvThree_default); 421 rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_FOUR, 422 R.bool.config_cecRcProfileTvFour_allowed, 423 R.bool.config_cecRcProfileTvFour_default); 424 425 Setting rcProfileSourceRootMenu = registerSetting( 426 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, 427 R.bool.config_cecRcProfileSourceRootMenu_userConfigurable); 428 rcProfileSourceRootMenu.registerValue( 429 HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED, 430 R.bool.config_cecRcProfileSourceRootMenuHandled_allowed, 431 R.bool.config_cecRcProfileSourceRootMenuHandled_default); 432 rcProfileSourceRootMenu.registerValue( 433 HdmiControlManager.RC_PROFILE_SOURCE_MENU_NOT_HANDLED, 434 R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed, 435 R.bool.config_cecRcProfileSourceRootMenuNotHandled_default); 436 437 Setting rcProfileSourceSetupMenu = registerSetting( 438 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, 439 R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable); 440 rcProfileSourceSetupMenu.registerValue( 441 HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED, 442 R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed, 443 R.bool.config_cecRcProfileSourceSetupMenuHandled_default); 444 rcProfileSourceSetupMenu.registerValue( 445 HdmiControlManager.RC_PROFILE_SOURCE_MENU_NOT_HANDLED, 446 R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed, 447 R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default); 448 449 Setting rcProfileSourceContentsMenu = registerSetting( 450 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, 451 R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable); 452 rcProfileSourceContentsMenu.registerValue( 453 HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED, 454 R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed, 455 R.bool.config_cecRcProfileSourceContentsMenuHandled_default); 456 rcProfileSourceContentsMenu.registerValue( 457 HdmiControlManager.RC_PROFILE_SOURCE_MENU_NOT_HANDLED, 458 R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed, 459 R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default); 460 461 Setting rcProfileSourceTopMenu = registerSetting( 462 HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, 463 R.bool.config_cecRcProfileSourceTopMenu_userConfigurable); 464 rcProfileSourceTopMenu.registerValue( 465 HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED, 466 R.bool.config_cecRcProfileSourceTopMenuHandled_allowed, 467 R.bool.config_cecRcProfileSourceTopMenuHandled_default); 468 rcProfileSourceTopMenu.registerValue( 469 HdmiControlManager.RC_PROFILE_SOURCE_MENU_NOT_HANDLED, 470 R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed, 471 R.bool.config_cecRcProfileSourceTopMenuNotHandled_default); 472 473 Setting rcProfileSourceMediaContextSensitiveMenu = registerSetting( 474 HdmiControlManager 475 .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU, 476 R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable); 477 rcProfileSourceMediaContextSensitiveMenu.registerValue( 478 HdmiControlManager.RC_PROFILE_SOURCE_MENU_HANDLED, 479 R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed, 480 R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default); 481 rcProfileSourceMediaContextSensitiveMenu.registerValue( 482 HdmiControlManager.RC_PROFILE_SOURCE_MENU_NOT_HANDLED, 483 R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed, 484 R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default); 485 486 Setting querySadLpcm = registerSetting( 487 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_LPCM, 488 R.bool.config_cecQuerySadLpcm_userConfigurable); 489 querySadLpcm.registerValue( 490 HdmiControlManager.QUERY_SAD_ENABLED, 491 R.bool.config_cecQuerySadLpcmEnabled_allowed, 492 R.bool.config_cecQuerySadLpcmEnabled_default); 493 querySadLpcm.registerValue( 494 HdmiControlManager.QUERY_SAD_DISABLED, 495 R.bool.config_cecQuerySadLpcmDisabled_allowed, 496 R.bool.config_cecQuerySadLpcmDisabled_default); 497 498 Setting querySadDd = registerSetting( 499 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DD, 500 R.bool.config_cecQuerySadDd_userConfigurable); 501 querySadDd.registerValue( 502 HdmiControlManager.QUERY_SAD_ENABLED, 503 R.bool.config_cecQuerySadDdEnabled_allowed, 504 R.bool.config_cecQuerySadDdEnabled_default); 505 querySadDd.registerValue( 506 HdmiControlManager.QUERY_SAD_DISABLED, 507 R.bool.config_cecQuerySadDdDisabled_allowed, 508 R.bool.config_cecQuerySadDdDisabled_default); 509 510 Setting querySadMpeg1 = registerSetting( 511 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1, 512 R.bool.config_cecQuerySadMpeg1_userConfigurable); 513 querySadMpeg1.registerValue( 514 HdmiControlManager.QUERY_SAD_ENABLED, 515 R.bool.config_cecQuerySadMpeg1Enabled_allowed, 516 R.bool.config_cecQuerySadMpeg1Enabled_default); 517 querySadMpeg1.registerValue( 518 HdmiControlManager.QUERY_SAD_DISABLED, 519 R.bool.config_cecQuerySadMpeg1Disabled_allowed, 520 R.bool.config_cecQuerySadMpeg1Disabled_default); 521 522 Setting querySadMp3 = registerSetting( 523 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MP3, 524 R.bool.config_cecQuerySadMp3_userConfigurable); 525 querySadMp3.registerValue( 526 HdmiControlManager.QUERY_SAD_ENABLED, 527 R.bool.config_cecQuerySadMp3Enabled_allowed, 528 R.bool.config_cecQuerySadMp3Enabled_default); 529 querySadMp3.registerValue( 530 HdmiControlManager.QUERY_SAD_DISABLED, 531 R.bool.config_cecQuerySadMp3Disabled_allowed, 532 R.bool.config_cecQuerySadMp3Disabled_default); 533 534 Setting querySadMpeg2 = registerSetting( 535 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG2, 536 R.bool.config_cecQuerySadMpeg2_userConfigurable); 537 querySadMpeg2.registerValue( 538 HdmiControlManager.QUERY_SAD_ENABLED, 539 R.bool.config_cecQuerySadMpeg2Enabled_allowed, 540 R.bool.config_cecQuerySadMpeg2Enabled_default); 541 querySadMpeg2.registerValue( 542 HdmiControlManager.QUERY_SAD_DISABLED, 543 R.bool.config_cecQuerySadMpeg2Disabled_allowed, 544 R.bool.config_cecQuerySadMpeg2Disabled_default); 545 546 Setting querySadAac = registerSetting( 547 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC, 548 R.bool.config_cecQuerySadAac_userConfigurable); 549 querySadAac.registerValue( 550 HdmiControlManager.QUERY_SAD_ENABLED, 551 R.bool.config_cecQuerySadAacEnabled_allowed, 552 R.bool.config_cecQuerySadAacEnabled_default); 553 querySadAac.registerValue( 554 HdmiControlManager.QUERY_SAD_DISABLED, 555 R.bool.config_cecQuerySadAacDisabled_allowed, 556 R.bool.config_cecQuerySadAacDisabled_default); 557 558 Setting querySadDts = registerSetting( 559 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS, 560 R.bool.config_cecQuerySadDts_userConfigurable); 561 querySadDts.registerValue( 562 HdmiControlManager.QUERY_SAD_ENABLED, 563 R.bool.config_cecQuerySadDtsEnabled_allowed, 564 R.bool.config_cecQuerySadDtsEnabled_default); 565 querySadDts.registerValue( 566 HdmiControlManager.QUERY_SAD_DISABLED, 567 R.bool.config_cecQuerySadDtsDisabled_allowed, 568 R.bool.config_cecQuerySadDtsDisabled_default); 569 570 Setting querySadAtrac = registerSetting( 571 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC, 572 R.bool.config_cecQuerySadAtrac_userConfigurable); 573 querySadAtrac.registerValue( 574 HdmiControlManager.QUERY_SAD_ENABLED, 575 R.bool.config_cecQuerySadAtracEnabled_allowed, 576 R.bool.config_cecQuerySadAtracEnabled_default); 577 querySadAtrac.registerValue( 578 HdmiControlManager.QUERY_SAD_DISABLED, 579 R.bool.config_cecQuerySadAtracDisabled_allowed, 580 R.bool.config_cecQuerySadAtracDisabled_default); 581 582 Setting querySadOnebitaudio = registerSetting( 583 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO, 584 R.bool.config_cecQuerySadOnebitaudio_userConfigurable); 585 querySadOnebitaudio.registerValue( 586 HdmiControlManager.QUERY_SAD_ENABLED, 587 R.bool.config_cecQuerySadOnebitaudioEnabled_allowed, 588 R.bool.config_cecQuerySadOnebitaudioEnabled_default); 589 querySadOnebitaudio.registerValue( 590 HdmiControlManager.QUERY_SAD_DISABLED, 591 R.bool.config_cecQuerySadOnebitaudioDisabled_allowed, 592 R.bool.config_cecQuerySadOnebitaudioDisabled_default); 593 594 Setting querySadDdp = registerSetting( 595 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP, 596 R.bool.config_cecQuerySadDdp_userConfigurable); 597 querySadDdp.registerValue( 598 HdmiControlManager.QUERY_SAD_ENABLED, 599 R.bool.config_cecQuerySadDdpEnabled_allowed, 600 R.bool.config_cecQuerySadDdpEnabled_default); 601 querySadDdp.registerValue( 602 HdmiControlManager.QUERY_SAD_DISABLED, 603 R.bool.config_cecQuerySadDdpDisabled_allowed, 604 R.bool.config_cecQuerySadDdpDisabled_default); 605 606 Setting querySadDtshd = registerSetting( 607 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD, 608 R.bool.config_cecQuerySadDtshd_userConfigurable); 609 querySadDtshd.registerValue( 610 HdmiControlManager.QUERY_SAD_ENABLED, 611 R.bool.config_cecQuerySadDtshdEnabled_allowed, 612 R.bool.config_cecQuerySadDtshdEnabled_default); 613 querySadDtshd.registerValue( 614 HdmiControlManager.QUERY_SAD_DISABLED, 615 R.bool.config_cecQuerySadDtshdDisabled_allowed, 616 R.bool.config_cecQuerySadDtshdDisabled_default); 617 618 Setting querySadTruehd = registerSetting( 619 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD, 620 R.bool.config_cecQuerySadTruehd_userConfigurable); 621 querySadTruehd.registerValue( 622 HdmiControlManager.QUERY_SAD_ENABLED, 623 R.bool.config_cecQuerySadTruehdEnabled_allowed, 624 R.bool.config_cecQuerySadTruehdEnabled_default); 625 querySadTruehd.registerValue( 626 HdmiControlManager.QUERY_SAD_DISABLED, 627 R.bool.config_cecQuerySadTruehdDisabled_allowed, 628 R.bool.config_cecQuerySadTruehdDisabled_default); 629 630 Setting querySadDst = registerSetting( 631 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST, 632 R.bool.config_cecQuerySadDst_userConfigurable); 633 querySadDst.registerValue( 634 HdmiControlManager.QUERY_SAD_ENABLED, 635 R.bool.config_cecQuerySadDstEnabled_allowed, 636 R.bool.config_cecQuerySadDstEnabled_default); 637 querySadDst.registerValue( 638 HdmiControlManager.QUERY_SAD_DISABLED, 639 R.bool.config_cecQuerySadDstDisabled_allowed, 640 R.bool.config_cecQuerySadDstDisabled_default); 641 642 Setting querySadWmapro = registerSetting( 643 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO, 644 R.bool.config_cecQuerySadWmapro_userConfigurable); 645 querySadWmapro.registerValue( 646 HdmiControlManager.QUERY_SAD_ENABLED, 647 R.bool.config_cecQuerySadWmaproEnabled_allowed, 648 R.bool.config_cecQuerySadWmaproEnabled_default); 649 querySadWmapro.registerValue( 650 HdmiControlManager.QUERY_SAD_DISABLED, 651 R.bool.config_cecQuerySadWmaproDisabled_allowed, 652 R.bool.config_cecQuerySadWmaproDisabled_default); 653 654 Setting querySadMax = registerSetting( 655 HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX, 656 R.bool.config_cecQuerySadMax_userConfigurable); 657 querySadMax.registerValue( 658 HdmiControlManager.QUERY_SAD_ENABLED, 659 R.bool.config_cecQuerySadMaxEnabled_allowed, 660 R.bool.config_cecQuerySadMaxEnabled_default); 661 querySadMax.registerValue( 662 HdmiControlManager.QUERY_SAD_DISABLED, 663 R.bool.config_cecQuerySadMaxDisabled_allowed, 664 R.bool.config_cecQuerySadMaxDisabled_default); 665 666 verifySettings(); 667 } 668 HdmiCecConfig(@onNull Context context)669 HdmiCecConfig(@NonNull Context context) { 670 this(context, new StorageAdapter(context)); 671 } 672 registerSetting(@onNull @ecSettingName String name, int userConfResId)673 private Setting registerSetting(@NonNull @CecSettingName String name, 674 int userConfResId) { 675 Setting setting = new Setting(mContext, name, userConfResId); 676 mSettings.put(name, setting); 677 return setting; 678 } 679 verifySettings()680 private void verifySettings() { 681 for (Setting setting: mSettings.values()) { 682 // This will throw an exception when a setting 683 // doesn't have a default value assigned. 684 setting.getDefaultValue(); 685 getStorage(setting); 686 getStorageKey(setting); 687 } 688 } 689 690 @Nullable getSetting(@onNull String name)691 private Setting getSetting(@NonNull String name) { 692 return mSettings.containsKey(name) ? mSettings.get(name) : null; 693 } 694 695 @Storage getStorage(@onNull Setting setting)696 private int getStorage(@NonNull Setting setting) { 697 switch (setting.getName()) { 698 case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED: 699 return STORAGE_SHARED_PREFS; 700 case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION: 701 return STORAGE_SHARED_PREFS; 702 case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL: 703 return STORAGE_SHARED_PREFS; 704 case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE: 705 return STORAGE_SHARED_PREFS; 706 case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE: 707 return STORAGE_SHARED_PREFS; 708 case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST: 709 return STORAGE_SHARED_PREFS; 710 case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL: 711 return STORAGE_SHARED_PREFS; 712 case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING: 713 return STORAGE_SHARED_PREFS; 714 case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY: 715 return STORAGE_SHARED_PREFS; 716 case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP: 717 return STORAGE_SHARED_PREFS; 718 case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE: 719 return STORAGE_SHARED_PREFS; 720 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV: 721 return STORAGE_SHARED_PREFS; 722 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU: 723 return STORAGE_SHARED_PREFS; 724 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU: 725 return STORAGE_SHARED_PREFS; 726 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU: 727 return STORAGE_SHARED_PREFS; 728 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU: 729 return STORAGE_SHARED_PREFS; 730 case HdmiControlManager 731 .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU: 732 return STORAGE_SHARED_PREFS; 733 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_LPCM: 734 return STORAGE_SHARED_PREFS; 735 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DD: 736 return STORAGE_SHARED_PREFS; 737 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1: 738 return STORAGE_SHARED_PREFS; 739 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MP3: 740 return STORAGE_SHARED_PREFS; 741 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG2: 742 return STORAGE_SHARED_PREFS; 743 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC: 744 return STORAGE_SHARED_PREFS; 745 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS: 746 return STORAGE_SHARED_PREFS; 747 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC: 748 return STORAGE_SHARED_PREFS; 749 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO: 750 return STORAGE_SHARED_PREFS; 751 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP: 752 return STORAGE_SHARED_PREFS; 753 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD: 754 return STORAGE_SHARED_PREFS; 755 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD: 756 return STORAGE_SHARED_PREFS; 757 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST: 758 return STORAGE_SHARED_PREFS; 759 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO: 760 return STORAGE_SHARED_PREFS; 761 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX: 762 return STORAGE_SHARED_PREFS; 763 default: 764 throw new VerificationException("Invalid CEC setting '" + setting.getName() 765 + "' storage."); 766 } 767 } 768 getStorageKey(@onNull Setting setting)769 private String getStorageKey(@NonNull Setting setting) { 770 switch (setting.getName()) { 771 case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED: 772 return setting.getName(); 773 case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION: 774 return setting.getName(); 775 case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL: 776 return setting.getName(); 777 case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE: 778 return setting.getName(); 779 case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE: 780 return setting.getName(); 781 case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST: 782 return setting.getName(); 783 case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL: 784 return setting.getName(); 785 case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING: 786 return setting.getName(); 787 case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY: 788 return setting.getName(); 789 case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP: 790 return setting.getName(); 791 case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE: 792 return setting.getName(); 793 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV: 794 return setting.getName(); 795 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU: 796 return setting.getName(); 797 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU: 798 return setting.getName(); 799 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU: 800 return setting.getName(); 801 case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU: 802 return setting.getName(); 803 case HdmiControlManager 804 .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU: 805 return setting.getName(); 806 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_LPCM: 807 return setting.getName(); 808 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DD: 809 return setting.getName(); 810 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1: 811 return setting.getName(); 812 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MP3: 813 return setting.getName(); 814 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG2: 815 return setting.getName(); 816 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC: 817 return setting.getName(); 818 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS: 819 return setting.getName(); 820 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC: 821 return setting.getName(); 822 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO: 823 return setting.getName(); 824 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP: 825 return setting.getName(); 826 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD: 827 return setting.getName(); 828 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD: 829 return setting.getName(); 830 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST: 831 return setting.getName(); 832 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO: 833 return setting.getName(); 834 case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX: 835 return setting.getName(); 836 default: 837 throw new VerificationException("Invalid CEC setting '" + setting.getName() 838 + "' storage key."); 839 } 840 } 841 retrieveValue(@onNull Setting setting, @NonNull String defaultValue)842 protected String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) { 843 @Storage int storage = getStorage(setting); 844 String storageKey = getStorageKey(setting); 845 if (storage == STORAGE_SYSPROPS) { 846 HdmiLogger.debug("Reading '" + storageKey + "' sysprop."); 847 return mStorageAdapter.retrieveSystemProperty(storageKey, defaultValue); 848 } else if (storage == STORAGE_GLOBAL_SETTINGS) { 849 HdmiLogger.debug("Reading '" + storageKey + "' global setting."); 850 return mStorageAdapter.retrieveGlobalSetting(storageKey, defaultValue); 851 } else if (storage == STORAGE_SHARED_PREFS) { 852 HdmiLogger.debug("Reading '" + storageKey + "' shared preference."); 853 return mStorageAdapter.retrieveSharedPref(storageKey, defaultValue); 854 } 855 return null; 856 } 857 storeValue(@onNull Setting setting, @NonNull String value)858 protected void storeValue(@NonNull Setting setting, @NonNull String value) { 859 @Storage int storage = getStorage(setting); 860 String storageKey = getStorageKey(setting); 861 if (storage == STORAGE_SYSPROPS) { 862 HdmiLogger.debug("Setting '" + storageKey + "' sysprop."); 863 mStorageAdapter.storeSystemProperty(storageKey, value); 864 } else if (storage == STORAGE_GLOBAL_SETTINGS) { 865 HdmiLogger.debug("Setting '" + storageKey + "' global setting."); 866 mStorageAdapter.storeGlobalSetting(storageKey, value); 867 } else if (storage == STORAGE_SHARED_PREFS) { 868 HdmiLogger.debug("Setting '" + storageKey + "' shared pref."); 869 mStorageAdapter.storeSharedPref(storageKey, value); 870 notifySettingChanged(setting); 871 } 872 } 873 notifySettingChanged(@onNull @ecSettingName String name)874 private void notifySettingChanged(@NonNull @CecSettingName String name) { 875 Setting setting = getSetting(name); 876 if (setting == null) { 877 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 878 } 879 notifySettingChanged(setting); 880 } 881 notifySettingChanged(@onNull Setting setting)882 protected void notifySettingChanged(@NonNull Setting setting) { 883 synchronized (mLock) { 884 ArrayMap<SettingChangeListener, Executor> listeners = 885 mSettingChangeListeners.get(setting); 886 if (listeners == null) { 887 return; // No listeners registered, do nothing. 888 } 889 for (Entry<SettingChangeListener, Executor> entry: listeners.entrySet()) { 890 SettingChangeListener listener = entry.getKey(); 891 Executor executor = entry.getValue(); 892 executor.execute(new Runnable() { 893 @Override 894 public void run() { 895 listener.onChange(setting.getName()); 896 } 897 }); 898 } 899 } 900 } 901 902 /** 903 * Register change listener for a given setting name using DirectExecutor. 904 */ registerChangeListener(@onNull @ecSettingName String name, SettingChangeListener listener)905 public void registerChangeListener(@NonNull @CecSettingName String name, 906 SettingChangeListener listener) { 907 registerChangeListener(name, listener, ConcurrentUtils.DIRECT_EXECUTOR); 908 } 909 910 /** 911 * Register change listener for a given setting name and executor. 912 */ registerChangeListener(@onNull @ecSettingName String name, SettingChangeListener listener, Executor executor)913 public void registerChangeListener(@NonNull @CecSettingName String name, 914 SettingChangeListener listener, 915 Executor executor) { 916 Setting setting = getSetting(name); 917 if (setting == null) { 918 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 919 } 920 @Storage int storage = getStorage(setting); 921 if (storage != STORAGE_GLOBAL_SETTINGS && storage != STORAGE_SHARED_PREFS) { 922 throw new IllegalArgumentException("Change listeners for setting '" + name 923 + "' not supported."); 924 } 925 synchronized (mLock) { 926 if (!mSettingChangeListeners.containsKey(setting)) { 927 mSettingChangeListeners.put(setting, new ArrayMap<>()); 928 } 929 mSettingChangeListeners.get(setting).put(listener, executor); 930 } 931 } 932 933 /** 934 * Remove change listener for a given setting name. 935 */ removeChangeListener(@onNull @ecSettingName String name, SettingChangeListener listener)936 public void removeChangeListener(@NonNull @CecSettingName String name, 937 SettingChangeListener listener) { 938 Setting setting = getSetting(name); 939 if (setting == null) { 940 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 941 } 942 synchronized (mLock) { 943 if (mSettingChangeListeners.containsKey(setting)) { 944 ArrayMap<SettingChangeListener, Executor> listeners = 945 mSettingChangeListeners.get(setting); 946 listeners.remove(listener); 947 if (listeners.isEmpty()) { 948 mSettingChangeListeners.remove(setting); 949 } 950 } 951 } 952 } 953 954 /** 955 * Returns a list of all settings based on the XML metadata. 956 */ getAllSettings()957 public @CecSettingName List<String> getAllSettings() { 958 return new ArrayList<>(mSettings.keySet()); 959 } 960 961 /** 962 * Returns a list of user-modifiable settings based on the XML metadata. 963 */ getUserSettings()964 public @CecSettingName List<String> getUserSettings() { 965 List<String> settings = new ArrayList<>(); 966 for (Setting setting: mSettings.values()) { 967 if (setting.getUserConfigurable()) { 968 settings.add(setting.getName()); 969 } 970 } 971 return settings; 972 } 973 974 /** 975 * For a given setting name returns true if and only if the value type of that 976 * setting is a string. 977 */ isStringValueType(@onNull @ecSettingName String name)978 public boolean isStringValueType(@NonNull @CecSettingName String name) { 979 Setting setting = getSetting(name); 980 if (setting == null) { 981 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 982 } 983 return getSetting(name).getValueType().equals(VALUE_TYPE_STRING); 984 } 985 986 /** 987 * For a given setting name returns true if and only if the value type of that 988 * setting is an int. 989 */ isIntValueType(@onNull @ecSettingName String name)990 public boolean isIntValueType(@NonNull @CecSettingName String name) { 991 Setting setting = getSetting(name); 992 if (setting == null) { 993 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 994 } 995 return getSetting(name).getValueType().equals(VALUE_TYPE_INT); 996 } 997 998 /** 999 * For a given setting name returns values that are allowed for that setting (string). 1000 */ getAllowedStringValues(@onNull @ecSettingName String name)1001 public List<String> getAllowedStringValues(@NonNull @CecSettingName String name) { 1002 Setting setting = getSetting(name); 1003 if (setting == null) { 1004 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1005 } 1006 if (!setting.getValueType().equals(VALUE_TYPE_STRING)) { 1007 throw new IllegalArgumentException("Setting '" + name 1008 + "' is not a string-type setting."); 1009 } 1010 List<String> allowedValues = new ArrayList<String>(); 1011 for (Value allowedValue : setting.getAllowedValues()) { 1012 allowedValues.add(allowedValue.getStringValue()); 1013 } 1014 return allowedValues; 1015 } 1016 1017 /** 1018 * For a given setting name returns values that are allowed for that setting (string). 1019 */ getAllowedIntValues(@onNull @ecSettingName String name)1020 public List<Integer> getAllowedIntValues(@NonNull @CecSettingName String name) { 1021 Setting setting = getSetting(name); 1022 if (setting == null) { 1023 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1024 } 1025 if (!setting.getValueType().equals(VALUE_TYPE_INT)) { 1026 throw new IllegalArgumentException("Setting '" + name 1027 + "' is not a string-type setting."); 1028 } 1029 List<Integer> allowedValues = new ArrayList<Integer>(); 1030 for (Value allowedValue : setting.getAllowedValues()) { 1031 allowedValues.add(allowedValue.getIntValue()); 1032 } 1033 return allowedValues; 1034 } 1035 1036 /** 1037 * For a given setting name returns the default value for that setting (string). 1038 */ getDefaultStringValue(@onNull @ecSettingName String name)1039 public String getDefaultStringValue(@NonNull @CecSettingName String name) { 1040 Setting setting = getSetting(name); 1041 if (setting == null) { 1042 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1043 } 1044 if (!setting.getValueType().equals(VALUE_TYPE_STRING)) { 1045 throw new IllegalArgumentException("Setting '" + name 1046 + "' is not a string-type setting."); 1047 } 1048 return getSetting(name).getDefaultValue().getStringValue(); 1049 } 1050 1051 /** 1052 * For a given setting name returns the default value for that setting (int). 1053 */ getDefaultIntValue(@onNull @ecSettingName String name)1054 public int getDefaultIntValue(@NonNull @CecSettingName String name) { 1055 Setting setting = getSetting(name); 1056 if (setting == null) { 1057 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1058 } 1059 if (!setting.getValueType().equals(VALUE_TYPE_INT)) { 1060 throw new IllegalArgumentException("Setting '" + name 1061 + "' is not a string-type setting."); 1062 } 1063 return getSetting(name).getDefaultValue().getIntValue(); 1064 } 1065 1066 /** 1067 * For a given setting name returns the current value of that setting (string). 1068 */ getStringValue(@onNull @ecSettingName String name)1069 public String getStringValue(@NonNull @CecSettingName String name) { 1070 Setting setting = getSetting(name); 1071 if (setting == null) { 1072 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1073 } 1074 if (!setting.getValueType().equals(VALUE_TYPE_STRING)) { 1075 throw new IllegalArgumentException("Setting '" + name 1076 + "' is not a string-type setting."); 1077 } 1078 HdmiLogger.debug("Getting CEC setting value '" + name + "'."); 1079 return retrieveValue(setting, setting.getDefaultValue().getStringValue()); 1080 } 1081 1082 /** 1083 * For a given setting name returns the current value of that setting (int). 1084 */ getIntValue(@onNull @ecSettingName String name)1085 public int getIntValue(@NonNull @CecSettingName String name) { 1086 Setting setting = getSetting(name); 1087 if (setting == null) { 1088 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1089 } 1090 if (!setting.getValueType().equals(VALUE_TYPE_INT)) { 1091 throw new IllegalArgumentException("Setting '" + name 1092 + "' is not a int-type setting."); 1093 } 1094 HdmiLogger.debug("Getting CEC setting value '" + name + "'."); 1095 String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue()); 1096 String value = retrieveValue(setting, defaultValue); 1097 return Integer.parseInt(value); 1098 } 1099 1100 /** 1101 * For a given setting name and value sets the current value of that setting (string). 1102 */ setStringValue(@onNull @ecSettingName String name, @NonNull String value)1103 public void setStringValue(@NonNull @CecSettingName String name, @NonNull String value) { 1104 Setting setting = getSetting(name); 1105 if (setting == null) { 1106 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1107 } 1108 if (!setting.getUserConfigurable()) { 1109 throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited."); 1110 } 1111 if (!setting.getValueType().equals(VALUE_TYPE_STRING)) { 1112 throw new IllegalArgumentException("Setting '" + name 1113 + "' is not a string-type setting."); 1114 } 1115 if (!getAllowedStringValues(name).contains(value)) { 1116 throw new IllegalArgumentException("Invalid CEC setting '" + name 1117 + "' value: '" + value + "'."); 1118 } 1119 HdmiLogger.debug("Updating CEC setting '" + name + "' to '" + value + "'."); 1120 storeValue(setting, value); 1121 } 1122 1123 /** 1124 * For a given setting name and value sets the current value of that setting (int). 1125 */ setIntValue(@onNull @ecSettingName String name, int value)1126 public void setIntValue(@NonNull @CecSettingName String name, int value) { 1127 Setting setting = getSetting(name); 1128 if (setting == null) { 1129 throw new IllegalArgumentException("Setting '" + name + "' does not exist."); 1130 } 1131 if (!setting.getUserConfigurable()) { 1132 throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited."); 1133 } 1134 if (!setting.getValueType().equals(VALUE_TYPE_INT)) { 1135 throw new IllegalArgumentException("Setting '" + name 1136 + "' is not a int-type setting."); 1137 } 1138 if (!getAllowedIntValues(name).contains(value)) { 1139 throw new IllegalArgumentException("Invalid CEC setting '" + name 1140 + "' value: '" + value + "'."); 1141 } 1142 HdmiLogger.debug("Updating CEC setting '" + name + "' to '" + value + "'."); 1143 storeValue(setting, Integer.toString(value)); 1144 } 1145 } 1146