diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-05-16 22:11:57 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-05-16 22:11:57 +0000 |
commit | 89777940b322690110689c7122f639c24ddfa82e (patch) | |
tree | 9bfe2facc1231cfdf0ca8a20ce1fe368c67affc4 | |
parent | 225abb0dfad71e96479a77976c9804c5b5e656f9 (diff) | |
parent | a80f5b947e751fe09db33a0f4f3d4330c29e246d (diff) | |
download | TvSettings-89777940b322690110689c7122f639c24ddfa82e.tar.gz |
Merge "Improved surround sound settings for ATV." into pi-dev
-rw-r--r-- | Settings/res/values/arrays.xml | 12 | ||||
-rw-r--r-- | Settings/res/xml/sound.xml | 23 | ||||
-rw-r--r-- | Settings/src/com/android/tv/settings/device/sound/SoundFormatPreferenceController.java | 141 | ||||
-rw-r--r-- | Settings/src/com/android/tv/settings/device/sound/SoundFragment.java | 120 |
4 files changed, 265 insertions, 31 deletions
diff --git a/Settings/res/values/arrays.xml b/Settings/res/values/arrays.xml index 41e4b99dd..810cc1be5 100644 --- a/Settings/res/values/arrays.xml +++ b/Settings/res/values/arrays.xml @@ -225,18 +225,18 @@ <item>FFFFFFFF</item> </string-array> - <!-- List entries for controlling surround sound passthrough setting [CHAR LIMIT=50] --> - <string-array name="surround_sound_entries"> - <item>Auto</item> - <item>Always</item> - <item>Never</item> + <!-- List entries for controlling surround sound passthrough setting --> + <string-array name="surround_sound_entries" translatable="false"> + <item>@string/surround_sound_auto_summary</item> + <item>@string/surround_sound_none_summary</item> + <item>@string/surround_sound_manual_summary</item> </string-array> <!-- Entry values for surround sound preference --> <string-array name="surround_sound_entry_values" translatable="false"> <item>auto</item> - <item>always</item> <item>never</item> + <item>manual</item> </string-array> <!-- Type of EAP method --> diff --git a/Settings/res/xml/sound.xml b/Settings/res/xml/sound.xml index 9b064c38b..b5f7aed4f 100644 --- a/Settings/res/xml/sound.xml +++ b/Settings/res/xml/sound.xml @@ -23,12 +23,21 @@ android:persistent="true" android:title="@string/device_sound_effects"/> - <ListPreference - android:key="surround_passthrough" - android:persistent="true" - android:entries="@array/surround_sound_entries" - android:entryValues="@array/surround_sound_entry_values" - android:title="@string/device_surround_sound" - android:summary="%s" /> + <PreferenceCategory + android:key="surround_sound_category" + android:title="@string/surround_sound_category_title"> + + <ListPreference + android:key="surround_passthrough" + android:persistent="true" + android:entries="@array/surround_sound_entries" + android:entryValues="@array/surround_sound_entry_values" + android:title="@string/surround_sound_select_formats" + android:summary="%s" + android:dialogMessage="@string/surround_sound_auto_info"/> + + <!-- Switches for each surround sound format programmatically added here. --> + + </PreferenceCategory> </PreferenceScreen> diff --git a/Settings/src/com/android/tv/settings/device/sound/SoundFormatPreferenceController.java b/Settings/src/com/android/tv/settings/device/sound/SoundFormatPreferenceController.java new file mode 100644 index 000000000..d36feee24 --- /dev/null +++ b/Settings/src/com/android/tv/settings/device/sound/SoundFormatPreferenceController.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tv.settings.device.sound; + +import android.content.Context; +import android.media.AudioManager; +import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.Preference; +import android.text.TextUtils; +import android.util.Log; + +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; + +/** + * Controller for the surround sound switch preferences. + */ +public class SoundFormatPreferenceController extends AbstractPreferenceController { + + private static final String TAG = "SoundFormatController"; + + private int mFormatId; + private AudioManager mAudioManager; + private Map<Integer, Boolean> mReportedFormats; + + public SoundFormatPreferenceController(Context context, int formatId) { + super(context); + mFormatId = formatId; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mReportedFormats = mAudioManager.getReportedSurroundFormats(); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public String getPreferenceKey() { + return SoundFragment.KEY_SURROUND_SOUND_FORMAT_PREFIX + mFormatId; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (preference.getKey().equals(getPreferenceKey())) { + preference.setEnabled(getFormatPreferencesEnabledState()); + ((SwitchPreference) preference).setChecked(getFormatPreferenceCheckedState()); + } + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (preference.getKey().equals(getPreferenceKey())) { + setSurroundManualFormatsSetting(((SwitchPreference) preference).isChecked()); + } + return super.handlePreferenceTreeClick(preference); + } + + /** + * @return checked state of a surround sound format switch based on passthrough setting and + * audio manager state for the format. + */ + private boolean getFormatPreferenceCheckedState() { + switch (SoundFragment.getSurroundPassthroughSetting(mContext)) { + case SoundFragment.VAL_SURROUND_SOUND_NEVER: + return false; + case SoundFragment.VAL_SURROUND_SOUND_ALWAYS: + return true; + case SoundFragment.VAL_SURROUND_SOUND_AUTO: + return isReportedFormat(); + case SoundFragment.VAL_SURROUND_SOUND_MANUAL: + return getFormatsEnabledInManualMode().contains(mFormatId); + default: return false; + } + } + + /** @return true if the format checkboxes should be enabled, i.e. in manual mode. */ + private boolean getFormatPreferencesEnabledState() { + return SoundFragment.getSurroundPassthroughSetting(mContext) + == SoundFragment.VAL_SURROUND_SOUND_MANUAL; + } + + /** @return the formats that are enabled in manual mode, from global settings */ + private HashSet<Integer> getFormatsEnabledInManualMode() { + HashSet<Integer> formats = new HashSet<>(); + String enabledFormats = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS); + if (enabledFormats == null) { + // Starting with Android P passthrough setting ALWAYS has been replaced with MANUAL. + // In that case all formats will be enabled when in MANUAL mode. + formats.addAll(mAudioManager.getSurroundFormats().keySet()); + } else { + try { + Arrays.stream(enabledFormats.split(",")).mapToInt(Integer::parseInt) + .forEach(formats::add); + } catch (NumberFormatException e) { + Log.w(TAG, "ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS misformatted.", e); + } + } + return formats; + } + + /** + * Writes enabled/disabled state for a given format to the global settings. + */ + private void setSurroundManualFormatsSetting(boolean enabled) { + HashSet<Integer> formats = getFormatsEnabledInManualMode(); + if (enabled) { + formats.add(mFormatId); + } else { + formats.remove(mFormatId); + } + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS, + TextUtils.join(",", formats)); + } + + /** @return true if the given format is reported by the device. */ + private boolean isReportedFormat() { + return mReportedFormats != null && mReportedFormats.get(mFormatId) != null; + } +} diff --git a/Settings/src/com/android/tv/settings/device/sound/SoundFragment.java b/Settings/src/com/android/tv/settings/device/sound/SoundFragment.java index 626fd3819..b929d0235 100644 --- a/Settings/src/com/android/tv/settings/device/sound/SoundFragment.java +++ b/Settings/src/com/android/tv/settings/device/sound/SoundFragment.java @@ -18,41 +18,61 @@ package com.android.tv.settings.device.sound; import android.content.ContentResolver; import android.content.Context; +import android.media.AudioFormat; import android.media.AudioManager; import android.os.Bundle; import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.TwoStatePreference; import android.text.TextUtils; import com.android.internal.logging.nano.MetricsProto; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.tv.settings.PreferenceControllerFragment; import com.android.tv.settings.R; -import com.android.tv.settings.SettingsPreferenceFragment; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * The "Sound" screen in TV Settings. */ -public class SoundFragment extends SettingsPreferenceFragment implements +public class SoundFragment extends PreferenceControllerFragment implements Preference.OnPreferenceChangeListener { - private static final String KEY_SOUND_EFFECTS = "sound_effects"; - private static final String KEY_SURROUND_PASSTHROUGH = "surround_passthrough"; + static final String KEY_SOUND_EFFECTS = "sound_effects"; + static final String KEY_SURROUND_PASSTHROUGH = "surround_passthrough"; + static final String KEY_SURROUND_SOUND_CATEGORY = "surround_sound_category"; + static final String KEY_SURROUND_SOUND_FORMAT_PREFIX = "surround_sound_format_"; - private static final String VAL_SURROUND_SOUND_AUTO = "auto"; - private static final String VAL_SURROUND_SOUND_ALWAYS = "always"; - private static final String VAL_SURROUND_SOUND_NEVER = "never"; + static final String VAL_SURROUND_SOUND_AUTO = "auto"; + static final String VAL_SURROUND_SOUND_NEVER = "never"; + static final String VAL_SURROUND_SOUND_ALWAYS = "always"; + static final String VAL_SURROUND_SOUND_MANUAL = "manual"; private AudioManager mAudioManager; + private Map<Integer, Boolean> mFormats; + private List<AbstractPreferenceController> mPreferenceControllers; + private PreferenceCategory mSurroundSoundCategoryPref; public static SoundFragment newInstance() { return new SoundFragment(); } @Override - public void onCreate(Bundle savedInstanceState) { - mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); - super.onCreate(savedInstanceState); + public void onAttach(Context context) { + mAudioManager = context.getSystemService(AudioManager.class); + mFormats = mAudioManager.getSurroundFormats(); + super.onAttach(context); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.sound; } @Override @@ -64,8 +84,65 @@ public class SoundFragment extends SettingsPreferenceFragment implements final ListPreference surroundPref = (ListPreference) findPreference(KEY_SURROUND_PASSTHROUGH); - surroundPref.setValue(getSurroundPassthroughSetting()); + surroundPref.setValue(getSurroundPassthroughSetting(getContext())); surroundPref.setOnPreferenceChangeListener(this); + + mSurroundSoundCategoryPref = + (PreferenceCategory) findPreference(KEY_SURROUND_SOUND_CATEGORY); + createFormatPreferences(); + updateFormatPreferencesStates(); + } + + @Override + protected List<AbstractPreferenceController> onCreatePreferenceControllers(Context context) { + mPreferenceControllers = new ArrayList<>(mFormats.size()); + for (Map.Entry<Integer, Boolean> format : mFormats.entrySet()) { + mPreferenceControllers.add(new SoundFormatPreferenceController(context, + format.getKey() /*formatId*/)); + } + return mPreferenceControllers; + } + + /** Creates and adds switches for each surround sound format. */ + private void createFormatPreferences() { + for (Map.Entry<Integer, Boolean> format : mFormats.entrySet()) { + int formatId = format.getKey(); + boolean enabled = format.getValue(); + SwitchPreference pref = new SwitchPreference(getPreferenceManager().getContext()); + pref.setTitle(getFormatDisplayName(formatId)); + pref.setKey(KEY_SURROUND_SOUND_FORMAT_PREFIX + formatId); + pref.setChecked(enabled); + mSurroundSoundCategoryPref.addPreference(pref); + } + } + + /** + * @return the display name for each surround sound format. + */ + private String getFormatDisplayName(int formatId) { + switch (formatId) { + case AudioFormat.ENCODING_AC3: + return getContext().getResources().getString(R.string.surround_sound_format_ac3); + case AudioFormat.ENCODING_E_AC3: + return getContext().getResources().getString(R.string.surround_sound_format_e_ac3); + case AudioFormat.ENCODING_DTS: + return getContext().getResources().getString(R.string.surround_sound_format_dts); + case AudioFormat.ENCODING_DTS_HD: + return getContext().getResources().getString(R.string.surround_sound_format_dts_hd); + default: + // Fallback in case new formats have been added that we don't know of. + return AudioFormat.toDisplayName(formatId); + } + } + + private void updateFormatPreferencesStates() { + for (AbstractPreferenceController controller : mPreferenceControllers) { + Preference preference = mSurroundSoundCategoryPref.findPreference( + controller.getPreferenceKey()); + if (preference != null) { + controller.updateState(preference); + } + } } @Override @@ -85,15 +162,20 @@ public class SoundFragment extends SettingsPreferenceFragment implements case VAL_SURROUND_SOUND_AUTO: setSurroundPassthroughSetting(Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO); break; + case VAL_SURROUND_SOUND_NEVER: + setSurroundPassthroughSetting(Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER); + break; case VAL_SURROUND_SOUND_ALWAYS: setSurroundPassthroughSetting(Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS); break; - case VAL_SURROUND_SOUND_NEVER: - setSurroundPassthroughSetting(Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER); + case VAL_SURROUND_SOUND_MANUAL: + setSurroundPassthroughSetting(Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL); break; default: - throw new IllegalArgumentException("Unknown surround sound pref value"); + throw new IllegalArgumentException("Unknown surround sound pref value: " + + selection); } + updateFormatPreferencesStates(); return true; } return true; @@ -123,8 +205,8 @@ public class SoundFragment extends SettingsPreferenceFragment implements Settings.Global.ENCODED_SURROUND_OUTPUT, newVal); } - private String getSurroundPassthroughSetting() { - final int value = Settings.Global.getInt(getContext().getContentResolver(), + static String getSurroundPassthroughSetting(Context context) { + final int value = Settings.Global.getInt(context.getContentResolver(), Settings.Global.ENCODED_SURROUND_OUTPUT, Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO); @@ -132,10 +214,12 @@ public class SoundFragment extends SettingsPreferenceFragment implements case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO: default: return VAL_SURROUND_SOUND_AUTO; - case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS: - return VAL_SURROUND_SOUND_ALWAYS; case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER: return VAL_SURROUND_SOUND_NEVER; + // On Android P ALWAYS is replaced by MANUAL. + case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS: + case Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL: + return VAL_SURROUND_SOUND_MANUAL; } } |