Loading src/com/android/settings/development/BluetoothA2dpSharedStore.java 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothCodecConfig; /** * Utility class for storing current Bluetooth A2DP profile values */ public class BluetoothA2dpSharedStore { // init default values private static int sCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID; private static int sCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private static int sSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE; private static int sBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE; private static int sChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE; private static long sCodecSpecific1Value = 0; private static long sCodecSpecific2Value = 0; private static long sCodecSpecific3Value = 0; private static long sCodecSpecific4Value = 0; public static int getCodecType() { return sCodecType; } public static int getCodecPriority() { return sCodecPriority; } public static int getSampleRate() { return sSampleRate; } public static int getBitsPerSample() { return sBitsPerSample; } public static int getChannelMode() { return sChannelMode; } public static long getCodecSpecific1Value() { return sCodecSpecific1Value; } public static long getCodecSpecific2Value() { return sCodecSpecific2Value; } public static long getCodecSpecific3Value() { return sCodecSpecific3Value; } public static long getCodecSpecific4Value() { return sCodecSpecific4Value; } public static void setCodecType(int codecType) { sCodecType = codecType; } public static void setCodecPriority(int codecPriority) { sCodecPriority = codecPriority; } public static void setSampleRate(int sampleRate) { sSampleRate = sampleRate; } public static void setBitsPerSample(int bitsPerSample) { sBitsPerSample = bitsPerSample; } public static void setChannelMode(int channelMode) { sChannelMode = channelMode; } public static void setCodecSpecific1Value(int codecSpecific1Value) { sCodecSpecific1Value = codecSpecific1Value; } public static void setCodecSpecific2Value(int codecSpecific2Value) { sCodecSpecific2Value = codecSpecific2Value; } public static void setCodecSpecific3Value(int codecSpecific3Value) { sCodecSpecific3Value = codecSpecific3Value; } public static void setCodecSpecific4Value(int codecSpecific4Value) { sCodecSpecific4Value = codecSpecific4Value; } } src/com/android/settings/development/BluetoothAudioSampleRatePreferenceController.java 0 → 100644 +243 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothCodecConfig; import android.content.Context; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.development.DeveloperOptionsPreferenceController; public class BluetoothAudioSampleRatePreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin, BluetoothServiceConnectionListener, LifecycleObserver, OnDestroy { private static final String BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY = "bluetooth_select_a2dp_sample_rate"; @VisibleForTesting static final int STREAMING_LABEL_ID = R.string.bluetooth_select_a2dp_codec_streaming_label; private final String[] mListValues; private final String[] mListSummaries; private final Object mBluetoothA2dpLock; private ListPreference mPreference; private BluetoothA2dp mBluetoothA2dp; public BluetoothAudioSampleRatePreferenceController(Context context, Lifecycle lifecycle, Object bluetoothA2dpLock) { super(context); mBluetoothA2dpLock = bluetoothA2dpLock; mListValues = context.getResources().getStringArray( R.array.bluetooth_a2dp_codec_sample_rate_values); mListSummaries = context.getResources().getStringArray( R.array.bluetooth_a2dp_codec_sample_rate_summaries); if (lifecycle != null) { lifecycle.addObserver(this); } } @Override public String getPreferenceKey() { return BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = (ListPreference) screen.findPreference(getPreferenceKey()); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (mBluetoothA2dp == null) { return false; } final int sampleRate = mapPreferenceValueToSampleRate(newValue.toString()); BluetoothA2dpSharedStore.setSampleRate(sampleRate); final int codecTypeValue = BluetoothA2dpSharedStore.getCodecType(); final int codecPriorityValue = BluetoothA2dpSharedStore.getCodecPriority(); final int sampleRateValue = BluetoothA2dpSharedStore.getSampleRate(); final int bitsPerSampleValue = BluetoothA2dpSharedStore.getBitsPerSample(); final int channelModeValue = BluetoothA2dpSharedStore.getChannelMode(); final long codecSpecific1Value = BluetoothA2dpSharedStore.getCodecSpecific1Value(); final long codecSpecific2Value = BluetoothA2dpSharedStore.getCodecSpecific2Value(); final long codecSpecific3Value = BluetoothA2dpSharedStore.getCodecSpecific3Value(); final long codecSpecific4Value = BluetoothA2dpSharedStore.getCodecSpecific4Value(); // get values from shared store BluetoothCodecConfig codecConfig = createCodecConfig(codecTypeValue, codecPriorityValue, sampleRateValue, bitsPerSampleValue, channelModeValue, codecSpecific1Value, codecSpecific2Value, codecSpecific3Value, codecSpecific4Value); synchronized (mBluetoothA2dpLock) { if (mBluetoothA2dp != null) { setCodecConfigPreference(codecConfig); } } updateState(mPreference); return true; } @Override public void updateState(Preference preference) { if (getCodecConfig() == null || mPreference == null) { return; } BluetoothCodecConfig codecConfig; synchronized (mBluetoothA2dpLock) { codecConfig = getCodecConfig(); } final int sampleRate = codecConfig.getSampleRate(); final int index = mapSampleRateToIndex(sampleRate); mPreference.setValue(mListValues[index]); mPreference.setSummary( mContext.getResources().getString(STREAMING_LABEL_ID, mListSummaries[index])); // write value to shared store BluetoothA2dpSharedStore.setSampleRate(sampleRate); } @Override public void onBluetoothServiceConnected(BluetoothA2dp bluetoothA2dp) { mBluetoothA2dp = bluetoothA2dp; updateState(mPreference); } @Override public void onBluetoothCodecUpdated() { updateState(mPreference); } @Override public void onBluetoothServiceDisconnected() { mBluetoothA2dp = null; } @Override public void onDestroy() { mBluetoothA2dp = null; } @Override protected void onDeveloperOptionsSwitchEnabled() { mPreference.setEnabled(true); } @Override protected void onDeveloperOptionsSwitchDisabled() { mPreference.setEnabled(false); } private int mapSampleRateToIndex(int sampleRate) { int index = 0; switch (sampleRate) { case BluetoothCodecConfig.SAMPLE_RATE_44100: index = 1; break; case BluetoothCodecConfig.SAMPLE_RATE_48000: index = 2; break; case BluetoothCodecConfig.SAMPLE_RATE_88200: index = 3; break; case BluetoothCodecConfig.SAMPLE_RATE_96000: index = 4; break; case BluetoothCodecConfig.SAMPLE_RATE_176400: case BluetoothCodecConfig.SAMPLE_RATE_192000: case BluetoothCodecConfig.SAMPLE_RATE_NONE: default: break; } return index; } private int mapPreferenceValueToSampleRate(String value) { final int index = mPreference.findIndexOfValue(value); int sampleRateValue = 0; switch (index) { case 0: // Reset to default sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_NONE; break; case 1: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_44100; break; case 2: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_48000; break; case 3: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_88200; break; case 4: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_96000; break; default: break; } return sampleRateValue; } @VisibleForTesting void setCodecConfigPreference(BluetoothCodecConfig config) { mBluetoothA2dp.setCodecConfigPreference(config); } @VisibleForTesting BluetoothCodecConfig getCodecConfig() { if (mBluetoothA2dp == null || mBluetoothA2dp.getCodecStatus() == null) { return null; } return mBluetoothA2dp.getCodecStatus().getCodecConfig(); } @VisibleForTesting BluetoothCodecConfig createCodecConfig(int codecTypeValue, int codecPriorityValue, int sampleRateValue, int bitsPerSampleValue, int channelModeValue, long codecSpecific1Value, long codecSpecific2Value, long codecSpecific3Value, long codecSpecific4Value) { return new BluetoothCodecConfig(codecTypeValue, codecPriorityValue, sampleRateValue, bitsPerSampleValue, channelModeValue, codecSpecific1Value, codecSpecific2Value, codecSpecific3Value, codecSpecific4Value); } } src/com/android/settings/development/BluetoothServiceConnectionListener.java 0 → 100644 +41 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothA2dp; /** * Interface for callbacks about bluetooth connectivity. */ public interface BluetoothServiceConnectionListener { /** * Called when the bluetooth service is connected. * @param bluetoothA2dp controller for Bluetooth A2DP profile. */ void onBluetoothServiceConnected(BluetoothA2dp bluetoothA2dp); /** * Called when the bluetooth codec configuration is changed. */ void onBluetoothCodecUpdated(); /** * Called with the bluetooth service is disconnected. */ void onBluetoothServiceDisconnected(); } src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +81 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package com.android.settings.development; import android.app.Activity; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; Loading Loading @@ -56,10 +60,13 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra private static final String TAG = "DevSettingsDashboard"; private final Object mBluetoothA2dpLock = new Object(); private boolean mIsAvailable = true; private SwitchBar mSwitchBar; private DevelopmentSwitchBarController mSwitchBarController; private List<AbstractPreferenceController> mPreferenceControllers = new ArrayList<>(); private BluetoothA2dp mBluetoothA2dp; private final BroadcastReceiver mEnableAdbReceiver = new BroadcastReceiver() { @Override Loading @@ -72,6 +79,56 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } }; private final BroadcastReceiver mBluetoothA2dpReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "mBluetoothA2dpReceiver.onReceive intent=" + intent); String action = intent.getAction(); if (BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED.equals(action)) { BluetoothCodecStatus codecStatus = intent.getParcelableExtra( BluetoothCodecStatus.EXTRA_CODEC_STATUS); Log.d(TAG, "Received BluetoothCodecStatus=" + codecStatus); for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller).onBluetoothCodecUpdated(); } } } } }; private final BluetoothProfile.ServiceListener mBluetoothA2dpServiceListener = new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { synchronized (mBluetoothA2dpLock) { mBluetoothA2dp = (BluetoothA2dp) proxy; } for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller) .onBluetoothServiceConnected(mBluetoothA2dp); } } } @Override public void onServiceDisconnected(int profile) { synchronized (mBluetoothA2dpLock) { mBluetoothA2dp = null; } for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller) .onBluetoothServiceDisconnected(); } } } }; public DevelopmentSettingsDashboardFragment() { super(UserManager.DISALLOW_DEBUGGING_FEATURES); } Loading Loading @@ -103,6 +160,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { registerReceivers(); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { adapter.getProfileProxy(getActivity(), mBluetoothA2dpServiceListener, BluetoothProfile.A2DP); } return super.onCreateView(inflater, container, savedInstanceState); } Loading @@ -110,6 +173,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public void onDestroyView() { super.onDestroyView(); unregisterReceivers(); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { adapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp); mBluetoothA2dp = null; } } @Override Loading Loading @@ -229,7 +298,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra @Override protected List<AbstractPreferenceController> getPreferenceControllers(Context context) { mPreferenceControllers = buildPreferenceControllers(context, getActivity(), getLifecycle(), this /* devOptionsDashboardFragment */); this /* devOptionsDashboardFragment */, mBluetoothA2dpLock); return mPreferenceControllers; } Loading @@ -237,10 +306,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra LocalBroadcastManager.getInstance(getContext()) .registerReceiver(mEnableAdbReceiver, new IntentFilter( AdbPreferenceController.ACTION_ENABLE_ADB_STATE_CHANGED)); final IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED); getActivity().registerReceiver(mBluetoothA2dpReceiver, filter); } private void unregisterReceivers() { LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mEnableAdbReceiver); getActivity().unregisterReceiver(mBluetoothA2dpReceiver); } void onEnableDevelopmentOptionsConfirmed() { Loading @@ -258,7 +332,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment) { Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment, Object bluetoothA2dpLock) { final List<AbstractPreferenceController> controllers = new ArrayList<>(); controllers.add(new BugReportPreferenceControllerV2(context)); controllers.add(new LocalBackupPasswordPreferenceController(context)); Loading Loading @@ -301,7 +376,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothInbandRingingPreferenceController(context)); controllers.add(new BluetoothAvrcpVersionPreferenceController(context)); // bluetooth audio codec // bluetooth audio sample rate controllers.add(new BluetoothAudioSampleRatePreferenceController(context, lifecycle, bluetoothA2dpLock)); // bluetooth audio bits per sample // bluetooth audio channel mode // bluetooth audio ldac codec: playback quality Loading Loading @@ -368,7 +444,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public List<AbstractPreferenceController> getPreferenceControllers(Context context) { return buildPreferenceControllers(context, null /* activity */, null /* lifecycle */, null /* devOptionsDashboardFragment */); null /* lifecycle */, null /* devOptionsDashboardFragment */, null /* bluetoothA2dpLock */); } }; } tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java +11 −0 Original line number Diff line number Diff line Loading @@ -20,4 +20,15 @@ package android.bluetooth; * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility. */ public class BluetoothCodecConfig { public static final int SAMPLE_RATE_NONE = 0; public static final int SAMPLE_RATE_48000 = 0x1 << 1; public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; public static final int CODEC_PRIORITY_DEFAULT = 0; public static final int BITS_PER_SAMPLE_NONE = 0; public static final int CHANNEL_MODE_NONE = 0; public int getSampleRate() { return 0; } } Loading
src/com/android/settings/development/BluetoothA2dpSharedStore.java 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothCodecConfig; /** * Utility class for storing current Bluetooth A2DP profile values */ public class BluetoothA2dpSharedStore { // init default values private static int sCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID; private static int sCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; private static int sSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE; private static int sBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE; private static int sChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE; private static long sCodecSpecific1Value = 0; private static long sCodecSpecific2Value = 0; private static long sCodecSpecific3Value = 0; private static long sCodecSpecific4Value = 0; public static int getCodecType() { return sCodecType; } public static int getCodecPriority() { return sCodecPriority; } public static int getSampleRate() { return sSampleRate; } public static int getBitsPerSample() { return sBitsPerSample; } public static int getChannelMode() { return sChannelMode; } public static long getCodecSpecific1Value() { return sCodecSpecific1Value; } public static long getCodecSpecific2Value() { return sCodecSpecific2Value; } public static long getCodecSpecific3Value() { return sCodecSpecific3Value; } public static long getCodecSpecific4Value() { return sCodecSpecific4Value; } public static void setCodecType(int codecType) { sCodecType = codecType; } public static void setCodecPriority(int codecPriority) { sCodecPriority = codecPriority; } public static void setSampleRate(int sampleRate) { sSampleRate = sampleRate; } public static void setBitsPerSample(int bitsPerSample) { sBitsPerSample = bitsPerSample; } public static void setChannelMode(int channelMode) { sChannelMode = channelMode; } public static void setCodecSpecific1Value(int codecSpecific1Value) { sCodecSpecific1Value = codecSpecific1Value; } public static void setCodecSpecific2Value(int codecSpecific2Value) { sCodecSpecific2Value = codecSpecific2Value; } public static void setCodecSpecific3Value(int codecSpecific3Value) { sCodecSpecific3Value = codecSpecific3Value; } public static void setCodecSpecific4Value(int codecSpecific4Value) { sCodecSpecific4Value = codecSpecific4Value; } }
src/com/android/settings/development/BluetoothAudioSampleRatePreferenceController.java 0 → 100644 +243 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothCodecConfig; import android.content.Context; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.development.DeveloperOptionsPreferenceController; public class BluetoothAudioSampleRatePreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin, BluetoothServiceConnectionListener, LifecycleObserver, OnDestroy { private static final String BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY = "bluetooth_select_a2dp_sample_rate"; @VisibleForTesting static final int STREAMING_LABEL_ID = R.string.bluetooth_select_a2dp_codec_streaming_label; private final String[] mListValues; private final String[] mListSummaries; private final Object mBluetoothA2dpLock; private ListPreference mPreference; private BluetoothA2dp mBluetoothA2dp; public BluetoothAudioSampleRatePreferenceController(Context context, Lifecycle lifecycle, Object bluetoothA2dpLock) { super(context); mBluetoothA2dpLock = bluetoothA2dpLock; mListValues = context.getResources().getStringArray( R.array.bluetooth_a2dp_codec_sample_rate_values); mListSummaries = context.getResources().getStringArray( R.array.bluetooth_a2dp_codec_sample_rate_summaries); if (lifecycle != null) { lifecycle.addObserver(this); } } @Override public String getPreferenceKey() { return BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = (ListPreference) screen.findPreference(getPreferenceKey()); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (mBluetoothA2dp == null) { return false; } final int sampleRate = mapPreferenceValueToSampleRate(newValue.toString()); BluetoothA2dpSharedStore.setSampleRate(sampleRate); final int codecTypeValue = BluetoothA2dpSharedStore.getCodecType(); final int codecPriorityValue = BluetoothA2dpSharedStore.getCodecPriority(); final int sampleRateValue = BluetoothA2dpSharedStore.getSampleRate(); final int bitsPerSampleValue = BluetoothA2dpSharedStore.getBitsPerSample(); final int channelModeValue = BluetoothA2dpSharedStore.getChannelMode(); final long codecSpecific1Value = BluetoothA2dpSharedStore.getCodecSpecific1Value(); final long codecSpecific2Value = BluetoothA2dpSharedStore.getCodecSpecific2Value(); final long codecSpecific3Value = BluetoothA2dpSharedStore.getCodecSpecific3Value(); final long codecSpecific4Value = BluetoothA2dpSharedStore.getCodecSpecific4Value(); // get values from shared store BluetoothCodecConfig codecConfig = createCodecConfig(codecTypeValue, codecPriorityValue, sampleRateValue, bitsPerSampleValue, channelModeValue, codecSpecific1Value, codecSpecific2Value, codecSpecific3Value, codecSpecific4Value); synchronized (mBluetoothA2dpLock) { if (mBluetoothA2dp != null) { setCodecConfigPreference(codecConfig); } } updateState(mPreference); return true; } @Override public void updateState(Preference preference) { if (getCodecConfig() == null || mPreference == null) { return; } BluetoothCodecConfig codecConfig; synchronized (mBluetoothA2dpLock) { codecConfig = getCodecConfig(); } final int sampleRate = codecConfig.getSampleRate(); final int index = mapSampleRateToIndex(sampleRate); mPreference.setValue(mListValues[index]); mPreference.setSummary( mContext.getResources().getString(STREAMING_LABEL_ID, mListSummaries[index])); // write value to shared store BluetoothA2dpSharedStore.setSampleRate(sampleRate); } @Override public void onBluetoothServiceConnected(BluetoothA2dp bluetoothA2dp) { mBluetoothA2dp = bluetoothA2dp; updateState(mPreference); } @Override public void onBluetoothCodecUpdated() { updateState(mPreference); } @Override public void onBluetoothServiceDisconnected() { mBluetoothA2dp = null; } @Override public void onDestroy() { mBluetoothA2dp = null; } @Override protected void onDeveloperOptionsSwitchEnabled() { mPreference.setEnabled(true); } @Override protected void onDeveloperOptionsSwitchDisabled() { mPreference.setEnabled(false); } private int mapSampleRateToIndex(int sampleRate) { int index = 0; switch (sampleRate) { case BluetoothCodecConfig.SAMPLE_RATE_44100: index = 1; break; case BluetoothCodecConfig.SAMPLE_RATE_48000: index = 2; break; case BluetoothCodecConfig.SAMPLE_RATE_88200: index = 3; break; case BluetoothCodecConfig.SAMPLE_RATE_96000: index = 4; break; case BluetoothCodecConfig.SAMPLE_RATE_176400: case BluetoothCodecConfig.SAMPLE_RATE_192000: case BluetoothCodecConfig.SAMPLE_RATE_NONE: default: break; } return index; } private int mapPreferenceValueToSampleRate(String value) { final int index = mPreference.findIndexOfValue(value); int sampleRateValue = 0; switch (index) { case 0: // Reset to default sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_NONE; break; case 1: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_44100; break; case 2: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_48000; break; case 3: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_88200; break; case 4: sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_96000; break; default: break; } return sampleRateValue; } @VisibleForTesting void setCodecConfigPreference(BluetoothCodecConfig config) { mBluetoothA2dp.setCodecConfigPreference(config); } @VisibleForTesting BluetoothCodecConfig getCodecConfig() { if (mBluetoothA2dp == null || mBluetoothA2dp.getCodecStatus() == null) { return null; } return mBluetoothA2dp.getCodecStatus().getCodecConfig(); } @VisibleForTesting BluetoothCodecConfig createCodecConfig(int codecTypeValue, int codecPriorityValue, int sampleRateValue, int bitsPerSampleValue, int channelModeValue, long codecSpecific1Value, long codecSpecific2Value, long codecSpecific3Value, long codecSpecific4Value) { return new BluetoothCodecConfig(codecTypeValue, codecPriorityValue, sampleRateValue, bitsPerSampleValue, channelModeValue, codecSpecific1Value, codecSpecific2Value, codecSpecific3Value, codecSpecific4Value); } }
src/com/android/settings/development/BluetoothServiceConnectionListener.java 0 → 100644 +41 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.development; import android.bluetooth.BluetoothA2dp; /** * Interface for callbacks about bluetooth connectivity. */ public interface BluetoothServiceConnectionListener { /** * Called when the bluetooth service is connected. * @param bluetoothA2dp controller for Bluetooth A2DP profile. */ void onBluetoothServiceConnected(BluetoothA2dp bluetoothA2dp); /** * Called when the bluetooth codec configuration is changed. */ void onBluetoothCodecUpdated(); /** * Called with the bluetooth service is disconnected. */ void onBluetoothServiceDisconnected(); }
src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +81 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package com.android.settings.development; import android.app.Activity; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; Loading Loading @@ -56,10 +60,13 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra private static final String TAG = "DevSettingsDashboard"; private final Object mBluetoothA2dpLock = new Object(); private boolean mIsAvailable = true; private SwitchBar mSwitchBar; private DevelopmentSwitchBarController mSwitchBarController; private List<AbstractPreferenceController> mPreferenceControllers = new ArrayList<>(); private BluetoothA2dp mBluetoothA2dp; private final BroadcastReceiver mEnableAdbReceiver = new BroadcastReceiver() { @Override Loading @@ -72,6 +79,56 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } }; private final BroadcastReceiver mBluetoothA2dpReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "mBluetoothA2dpReceiver.onReceive intent=" + intent); String action = intent.getAction(); if (BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED.equals(action)) { BluetoothCodecStatus codecStatus = intent.getParcelableExtra( BluetoothCodecStatus.EXTRA_CODEC_STATUS); Log.d(TAG, "Received BluetoothCodecStatus=" + codecStatus); for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller).onBluetoothCodecUpdated(); } } } } }; private final BluetoothProfile.ServiceListener mBluetoothA2dpServiceListener = new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { synchronized (mBluetoothA2dpLock) { mBluetoothA2dp = (BluetoothA2dp) proxy; } for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller) .onBluetoothServiceConnected(mBluetoothA2dp); } } } @Override public void onServiceDisconnected(int profile) { synchronized (mBluetoothA2dpLock) { mBluetoothA2dp = null; } for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothServiceConnectionListener) { ((BluetoothServiceConnectionListener) controller) .onBluetoothServiceDisconnected(); } } } }; public DevelopmentSettingsDashboardFragment() { super(UserManager.DISALLOW_DEBUGGING_FEATURES); } Loading Loading @@ -103,6 +160,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { registerReceivers(); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { adapter.getProfileProxy(getActivity(), mBluetoothA2dpServiceListener, BluetoothProfile.A2DP); } return super.onCreateView(inflater, container, savedInstanceState); } Loading @@ -110,6 +173,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public void onDestroyView() { super.onDestroyView(); unregisterReceivers(); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { adapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp); mBluetoothA2dp = null; } } @Override Loading Loading @@ -229,7 +298,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra @Override protected List<AbstractPreferenceController> getPreferenceControllers(Context context) { mPreferenceControllers = buildPreferenceControllers(context, getActivity(), getLifecycle(), this /* devOptionsDashboardFragment */); this /* devOptionsDashboardFragment */, mBluetoothA2dpLock); return mPreferenceControllers; } Loading @@ -237,10 +306,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra LocalBroadcastManager.getInstance(getContext()) .registerReceiver(mEnableAdbReceiver, new IntentFilter( AdbPreferenceController.ACTION_ENABLE_ADB_STATE_CHANGED)); final IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED); getActivity().registerReceiver(mBluetoothA2dpReceiver, filter); } private void unregisterReceivers() { LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mEnableAdbReceiver); getActivity().unregisterReceiver(mBluetoothA2dpReceiver); } void onEnableDevelopmentOptionsConfirmed() { Loading @@ -258,7 +332,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment) { Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment, Object bluetoothA2dpLock) { final List<AbstractPreferenceController> controllers = new ArrayList<>(); controllers.add(new BugReportPreferenceControllerV2(context)); controllers.add(new LocalBackupPasswordPreferenceController(context)); Loading Loading @@ -301,7 +376,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothInbandRingingPreferenceController(context)); controllers.add(new BluetoothAvrcpVersionPreferenceController(context)); // bluetooth audio codec // bluetooth audio sample rate controllers.add(new BluetoothAudioSampleRatePreferenceController(context, lifecycle, bluetoothA2dpLock)); // bluetooth audio bits per sample // bluetooth audio channel mode // bluetooth audio ldac codec: playback quality Loading Loading @@ -368,7 +444,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra public List<AbstractPreferenceController> getPreferenceControllers(Context context) { return buildPreferenceControllers(context, null /* activity */, null /* lifecycle */, null /* devOptionsDashboardFragment */); null /* lifecycle */, null /* devOptionsDashboardFragment */, null /* bluetoothA2dpLock */); } }; }
tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java +11 −0 Original line number Diff line number Diff line Loading @@ -20,4 +20,15 @@ package android.bluetooth; * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility. */ public class BluetoothCodecConfig { public static final int SAMPLE_RATE_NONE = 0; public static final int SAMPLE_RATE_48000 = 0x1 << 1; public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; public static final int CODEC_PRIORITY_DEFAULT = 0; public static final int BITS_PER_SAMPLE_NONE = 0; public static final int CHANNEL_MODE_NONE = 0; public int getSampleRate() { return 0; } }