Loading res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -260,6 +260,13 @@ <string name="bluetooth_disable_leaudio_summary">Disables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string> <!-- Setting toggle title for switch Bluetooth LE Audio mode. [CHAR LIMIT=40] --> <string name="bluetooth_leaudio_mode">Bluetooth LE Audio mode</string> <!-- Setting toggle title for enabling Bluetooth LE Audio UI preview. [CHAR LIMIT=none] --> <string name="bluetooth_leaudio_broadcast_ui">Enable Bluetooth LE Audio Broadcast UI preview</string> <!-- Summary of toggle for enabling Bluetooth LE Audio UI preview. [CHAR LIMIT=none]--> <string name="bluetooth_leaudio_broadcast_ui_summary">Enables the LE Audio Sharing UI preview including personal audio sharing and private broadcast</string> <!-- Setting toggle title for enabling Bluetooth LE Audio toggle in Device Details. [CHAR LIMIT=40] --> <string name="bluetooth_show_leaudio_device_details">Show LE audio toggle in Device Details</string> res/xml/development_settings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,11 @@ android:entries="@array/bluetooth_leaudio_mode" android:entryValues="@array/bluetooth_leaudio_mode_values"/> <SwitchPreferenceCompat android:key="bluetooth_leaudio_broadcast_ui" android:title="@string/bluetooth_leaudio_broadcast_ui" android:summary="@string/bluetooth_leaudio_broadcast_ui_summary"/> <SwitchPreferenceCompat android:key="bluetooth_show_leaudio_device_details" android:title="@string/bluetooth_show_leaudio_device_details"/> Loading src/com/android/settings/development/BluetoothLeAudioModePreferenceController.java +20 −18 Original line number Diff line number Diff line Loading @@ -34,12 +34,10 @@ import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import java.util.Objects; /** * Preference controller to control Bluetooth LE audio mode */ public class BluetoothLeAudioModePreferenceController extends DeveloperOptionsPreferenceController /** Preference controller to control Bluetooth LE audio mode */ public class BluetoothLeAudioModePreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String PREFERENCE_KEY = "bluetooth_leaudio_mode"; Loading @@ -51,15 +49,13 @@ public class BluetoothLeAudioModePreferenceController private final String[] mListValues; private final String[] mListSummaries; @VisibleForTesting @Nullable String mNewMode; @VisibleForTesting BluetoothAdapter mBluetoothAdapter; @VisibleForTesting @Nullable String mNewMode; @VisibleForTesting BluetoothAdapter mBluetoothAdapter; boolean mChanged = false; public BluetoothLeAudioModePreferenceController(@NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { public BluetoothLeAudioModePreferenceController( @NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { super(context); mFragment = fragment; mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); Loading @@ -69,7 +65,8 @@ public class BluetoothLeAudioModePreferenceController } @Override @NonNull public String getPreferenceKey() { @NonNull public String getPreferenceKey() { return PREFERENCE_KEY; } Loading Loading @@ -125,20 +122,25 @@ public class BluetoothLeAudioModePreferenceController } } /** * Called when the RebootDialog confirm is clicked. */ /** Called when the RebootDialog confirm is clicked. */ public void onRebootDialogConfirmed() { if (!mChanged) { return; } SystemProperties.set(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mNewMode); if (mFragment != null && !Objects.equals(mNewMode, "broadcast")) { mFragment.onBroadcastDisabled(); } } /** * Called when the RebootDialog cancel is clicked. */ /** Called when the RebootDialog cancel is clicked. */ public void onRebootDialogCanceled() { mChanged = false; } public interface OnModeChangeListener { /** Called when the broadcast mode is disabled. */ void onBroadcastDisabled(); } } src/com/android/settings/development/BluetoothLeAudioUiPreferenceController.java 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.BluetoothAdapter; import android.bluetooth.BluetoothStatusCodes; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.sysprop.BluetoothProperties; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.SwitchPreferenceCompat; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.settingslib.flags.Flags; import com.android.settingslib.utils.ThreadUtils; /** Preference controller to enable / disable the Bluetooth LE audio sharing UI flow */ public class BluetoothLeAudioUiPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin, BluetoothLeAudioModePreferenceController.OnModeChangeListener { private static final String TAG = "BluetoothLeAudioUiPreferenceController"; private static final String PREFERENCE_KEY = "bluetooth_leaudio_broadcast_ui"; @VisibleForTesting static final String VALUE_KEY = "bluetooth_le_audio_sharing_ui_preview_enabled"; @VisibleForTesting static final int VALUE_OFF = 0; @VisibleForTesting static final int VALUE_ON = 1; @VisibleForTesting static final int VALUE_UNSET = -1; @Nullable private final DevelopmentSettingsDashboardFragment mFragment; private final BluetoothAdapter mBluetoothAdapter; private boolean mCurrentSettingsValue = false; private boolean mShouldToggleCurrentValue = false; public BluetoothLeAudioUiPreferenceController( @NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { super(context); mFragment = fragment; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @Override public boolean isAvailable() { return Flags.audioSharingDeveloperOption() && BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false) && BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false); } @Override public boolean onPreferenceChange(@NonNull Preference preference, @Nullable Object newValue) { if (mFragment != null && newValue != null && (boolean) newValue != mCurrentSettingsValue) { mShouldToggleCurrentValue = true; BluetoothRebootDialog.show(mFragment); } return false; } @Override public void updateState(@NonNull Preference preference) { if (mBluetoothAdapter == null) { return; } var unused = ThreadUtils.postOnBackgroundThread( () -> { boolean shouldEnable = mBluetoothAdapter.isEnabled() && mBluetoothAdapter.isLeAudioBroadcastSourceSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED && mBluetoothAdapter.isLeAudioBroadcastAssistantSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED; boolean valueOn = Settings.Global.getInt( mContext.getContentResolver(), VALUE_KEY, VALUE_UNSET) == VALUE_ON; mContext.getMainExecutor() .execute( () -> { if (!shouldEnable && valueOn) { Log.e( TAG, "Error state: toggle disabled but current" + " settings value is true."); } mCurrentSettingsValue = valueOn; preference.setEnabled(shouldEnable); ((SwitchPreferenceCompat) preference).setChecked(valueOn); }); }); } @Override public @NonNull String getPreferenceKey() { return PREFERENCE_KEY; } /** Called when the RebootDialog confirm is clicked. */ public void onRebootDialogConfirmed() { if (isAvailable() && mShouldToggleCurrentValue) { // Blocking, ensure reboot happens after value is saved. Log.d(TAG, "onRebootDialogConfirmed(): setting value to " + !mCurrentSettingsValue); toggleSetting(mContext.getContentResolver(), !mCurrentSettingsValue); } } /** Called when the RebootDialog cancel is clicked. */ public void onRebootDialogCanceled() { mShouldToggleCurrentValue = false; } @Override public void onBroadcastDisabled() { if (isAvailable() && mCurrentSettingsValue) { Log.d(TAG, "onBroadcastDisabled(): setting value to false"); // Blocking, ensure reboot happens after value is saved. toggleSetting(mContext.getContentResolver(), false); } } private static void toggleSetting(ContentResolver contentResolver, boolean valueOn) { Settings.Global.putInt(contentResolver, VALUE_KEY, valueOn ? VALUE_ON : VALUE_OFF); } } src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +21 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,9 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra AdbClearKeysDialogHost, LogPersistDialogHost, BluetoothRebootDialog.OnRebootDialogListener, AbstractBluetoothPreferenceController.Callback, NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost { NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost, BluetoothLeAudioModePreferenceController.OnModeChangeListener { private static final String TAG = "DevSettingsDashboard"; @VisibleForTesting static final int REQUEST_BIOMETRIC_PROMPT = 100; Loading Loading @@ -498,6 +500,10 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioModePreferenceController.class); leAudioModeController.onRebootDialogConfirmed(); final BluetoothLeAudioUiPreferenceController leAudioUiController = getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); leAudioUiController.onRebootDialogConfirmed(); } @Override Loading @@ -520,6 +526,10 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioModePreferenceController.class); leAudioModeController.onRebootDialogCanceled(); final BluetoothLeAudioUiPreferenceController leAudioUiController = getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); leAudioUiController.onRebootDialogCanceled(); } @Override Loading Loading @@ -741,6 +751,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothMapVersionPreferenceController(context)); controllers.add(new BluetoothLeAudioPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioModePreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioUiPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioDeviceDetailsPreferenceController(context)); controllers.add(new BluetoothLeAudioAllowListPreferenceController(context)); controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment)); Loading Loading @@ -858,6 +869,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } } @Override public void onBroadcastDisabled() { for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothLeAudioUiPreferenceController) { ((BluetoothLeAudioUiPreferenceController) controller).onBroadcastDisabled(); } } } /** * For Search. */ Loading Loading
res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -260,6 +260,13 @@ <string name="bluetooth_disable_leaudio_summary">Disables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string> <!-- Setting toggle title for switch Bluetooth LE Audio mode. [CHAR LIMIT=40] --> <string name="bluetooth_leaudio_mode">Bluetooth LE Audio mode</string> <!-- Setting toggle title for enabling Bluetooth LE Audio UI preview. [CHAR LIMIT=none] --> <string name="bluetooth_leaudio_broadcast_ui">Enable Bluetooth LE Audio Broadcast UI preview</string> <!-- Summary of toggle for enabling Bluetooth LE Audio UI preview. [CHAR LIMIT=none]--> <string name="bluetooth_leaudio_broadcast_ui_summary">Enables the LE Audio Sharing UI preview including personal audio sharing and private broadcast</string> <!-- Setting toggle title for enabling Bluetooth LE Audio toggle in Device Details. [CHAR LIMIT=40] --> <string name="bluetooth_show_leaudio_device_details">Show LE audio toggle in Device Details</string>
res/xml/development_settings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,11 @@ android:entries="@array/bluetooth_leaudio_mode" android:entryValues="@array/bluetooth_leaudio_mode_values"/> <SwitchPreferenceCompat android:key="bluetooth_leaudio_broadcast_ui" android:title="@string/bluetooth_leaudio_broadcast_ui" android:summary="@string/bluetooth_leaudio_broadcast_ui_summary"/> <SwitchPreferenceCompat android:key="bluetooth_show_leaudio_device_details" android:title="@string/bluetooth_show_leaudio_device_details"/> Loading
src/com/android/settings/development/BluetoothLeAudioModePreferenceController.java +20 −18 Original line number Diff line number Diff line Loading @@ -34,12 +34,10 @@ import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import java.util.Objects; /** * Preference controller to control Bluetooth LE audio mode */ public class BluetoothLeAudioModePreferenceController extends DeveloperOptionsPreferenceController /** Preference controller to control Bluetooth LE audio mode */ public class BluetoothLeAudioModePreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String PREFERENCE_KEY = "bluetooth_leaudio_mode"; Loading @@ -51,15 +49,13 @@ public class BluetoothLeAudioModePreferenceController private final String[] mListValues; private final String[] mListSummaries; @VisibleForTesting @Nullable String mNewMode; @VisibleForTesting BluetoothAdapter mBluetoothAdapter; @VisibleForTesting @Nullable String mNewMode; @VisibleForTesting BluetoothAdapter mBluetoothAdapter; boolean mChanged = false; public BluetoothLeAudioModePreferenceController(@NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { public BluetoothLeAudioModePreferenceController( @NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { super(context); mFragment = fragment; mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); Loading @@ -69,7 +65,8 @@ public class BluetoothLeAudioModePreferenceController } @Override @NonNull public String getPreferenceKey() { @NonNull public String getPreferenceKey() { return PREFERENCE_KEY; } Loading Loading @@ -125,20 +122,25 @@ public class BluetoothLeAudioModePreferenceController } } /** * Called when the RebootDialog confirm is clicked. */ /** Called when the RebootDialog confirm is clicked. */ public void onRebootDialogConfirmed() { if (!mChanged) { return; } SystemProperties.set(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mNewMode); if (mFragment != null && !Objects.equals(mNewMode, "broadcast")) { mFragment.onBroadcastDisabled(); } } /** * Called when the RebootDialog cancel is clicked. */ /** Called when the RebootDialog cancel is clicked. */ public void onRebootDialogCanceled() { mChanged = false; } public interface OnModeChangeListener { /** Called when the broadcast mode is disabled. */ void onBroadcastDisabled(); } }
src/com/android/settings/development/BluetoothLeAudioUiPreferenceController.java 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.BluetoothAdapter; import android.bluetooth.BluetoothStatusCodes; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.sysprop.BluetoothProperties; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.SwitchPreferenceCompat; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import com.android.settingslib.flags.Flags; import com.android.settingslib.utils.ThreadUtils; /** Preference controller to enable / disable the Bluetooth LE audio sharing UI flow */ public class BluetoothLeAudioUiPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin, BluetoothLeAudioModePreferenceController.OnModeChangeListener { private static final String TAG = "BluetoothLeAudioUiPreferenceController"; private static final String PREFERENCE_KEY = "bluetooth_leaudio_broadcast_ui"; @VisibleForTesting static final String VALUE_KEY = "bluetooth_le_audio_sharing_ui_preview_enabled"; @VisibleForTesting static final int VALUE_OFF = 0; @VisibleForTesting static final int VALUE_ON = 1; @VisibleForTesting static final int VALUE_UNSET = -1; @Nullable private final DevelopmentSettingsDashboardFragment mFragment; private final BluetoothAdapter mBluetoothAdapter; private boolean mCurrentSettingsValue = false; private boolean mShouldToggleCurrentValue = false; public BluetoothLeAudioUiPreferenceController( @NonNull Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) { super(context); mFragment = fragment; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @Override public boolean isAvailable() { return Flags.audioSharingDeveloperOption() && BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false) && BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false); } @Override public boolean onPreferenceChange(@NonNull Preference preference, @Nullable Object newValue) { if (mFragment != null && newValue != null && (boolean) newValue != mCurrentSettingsValue) { mShouldToggleCurrentValue = true; BluetoothRebootDialog.show(mFragment); } return false; } @Override public void updateState(@NonNull Preference preference) { if (mBluetoothAdapter == null) { return; } var unused = ThreadUtils.postOnBackgroundThread( () -> { boolean shouldEnable = mBluetoothAdapter.isEnabled() && mBluetoothAdapter.isLeAudioBroadcastSourceSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED && mBluetoothAdapter.isLeAudioBroadcastAssistantSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED; boolean valueOn = Settings.Global.getInt( mContext.getContentResolver(), VALUE_KEY, VALUE_UNSET) == VALUE_ON; mContext.getMainExecutor() .execute( () -> { if (!shouldEnable && valueOn) { Log.e( TAG, "Error state: toggle disabled but current" + " settings value is true."); } mCurrentSettingsValue = valueOn; preference.setEnabled(shouldEnable); ((SwitchPreferenceCompat) preference).setChecked(valueOn); }); }); } @Override public @NonNull String getPreferenceKey() { return PREFERENCE_KEY; } /** Called when the RebootDialog confirm is clicked. */ public void onRebootDialogConfirmed() { if (isAvailable() && mShouldToggleCurrentValue) { // Blocking, ensure reboot happens after value is saved. Log.d(TAG, "onRebootDialogConfirmed(): setting value to " + !mCurrentSettingsValue); toggleSetting(mContext.getContentResolver(), !mCurrentSettingsValue); } } /** Called when the RebootDialog cancel is clicked. */ public void onRebootDialogCanceled() { mShouldToggleCurrentValue = false; } @Override public void onBroadcastDisabled() { if (isAvailable() && mCurrentSettingsValue) { Log.d(TAG, "onBroadcastDisabled(): setting value to false"); // Blocking, ensure reboot happens after value is saved. toggleSetting(mContext.getContentResolver(), false); } } private static void toggleSetting(ContentResolver contentResolver, boolean valueOn) { Settings.Global.putInt(contentResolver, VALUE_KEY, valueOn ? VALUE_ON : VALUE_OFF); } }
src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +21 −1 Original line number Diff line number Diff line Loading @@ -99,7 +99,9 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra AdbClearKeysDialogHost, LogPersistDialogHost, BluetoothRebootDialog.OnRebootDialogListener, AbstractBluetoothPreferenceController.Callback, NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost { NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost, BluetoothLeAudioModePreferenceController.OnModeChangeListener { private static final String TAG = "DevSettingsDashboard"; @VisibleForTesting static final int REQUEST_BIOMETRIC_PROMPT = 100; Loading Loading @@ -498,6 +500,10 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioModePreferenceController.class); leAudioModeController.onRebootDialogConfirmed(); final BluetoothLeAudioUiPreferenceController leAudioUiController = getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); leAudioUiController.onRebootDialogConfirmed(); } @Override Loading @@ -520,6 +526,10 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra getDevelopmentOptionsController( BluetoothLeAudioModePreferenceController.class); leAudioModeController.onRebootDialogCanceled(); final BluetoothLeAudioUiPreferenceController leAudioUiController = getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); leAudioUiController.onRebootDialogCanceled(); } @Override Loading Loading @@ -741,6 +751,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothMapVersionPreferenceController(context)); controllers.add(new BluetoothLeAudioPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioModePreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioUiPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioDeviceDetailsPreferenceController(context)); controllers.add(new BluetoothLeAudioAllowListPreferenceController(context)); controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment)); Loading Loading @@ -858,6 +869,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra } } @Override public void onBroadcastDisabled() { for (AbstractPreferenceController controller : mPreferenceControllers) { if (controller instanceof BluetoothLeAudioUiPreferenceController) { ((BluetoothLeAudioUiPreferenceController) controller).onBroadcastDisabled(); } } } /** * For Search. */ Loading