Merge changes I0ea498d2,I2d650eb3,I8adcf27e

* changes:
  Grey out LE audio offload switcher as LE audio isn't enabled/supported
  Unify the LE audio string and refine the layout to put LE audio switch together
  Add LE Audio feature switcher in the developer option menu
This commit is contained in:
Treehugger Robot
2022-06-06 06:37:11 +00:00
committed by Gerrit Code Review
10 changed files with 307 additions and 44 deletions

View File

@@ -329,8 +329,8 @@
<!-- UI debug setting: Disable Bluetooth A2DP hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_a2dp_hw_offload">Disable Bluetooth A2DP hardware offload</string>
<!-- UI debug setting: Disable Bluetooth LE AUDIO hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_le_audio_hw_offload">Disable Bluetooth LE AUDIO hardware offload</string>
<!-- UI debug setting: Disable Bluetooth LE audio hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_le_audio_hw_offload">Disable Bluetooth LE audio hardware offload</string>
<!-- UI debug setting: Disable Bluetooth hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_hw_offload_dialog_title">Restart Device?</string>
<!-- UI debug setting: Disable Bluetooth hardware offload [CHAR LIMIT=none] -->
@@ -340,6 +340,11 @@
<!-- UI debug setting: Disable Bluetooth hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_hw_offload_dialog_cancel">Cancel</string>
<!-- Setting Checkbox title for enabling Bluetooth LE Audio feature. [CHAR LIMIT=40] -->
<string name="bluetooth_enable_leaudio">Enable Bluetooth LE audio</string>
<!-- Summary of checkbox for enabling Bluetooth LE audio [CHAR LIMIT=none]-->
<string name="bluetooth_enable_leaudio_summary">Enables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
<string name="connected_device_media_device_title">Media devices</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->

View File

@@ -308,13 +308,18 @@
android:summary="@string/bluetooth_disable_absolute_volume_summary" />
<SwitchPreference
android:key="bluetooth_disable_a2dp_hw_offload"
android:title="@string/bluetooth_disable_a2dp_hw_offload" />
android:key="bluetooth_enable_leaudio"
android:title="@string/bluetooth_enable_leaudio"
android:summary="@string/bluetooth_enable_leaudio_summary" />
<SwitchPreference
android:key="bluetooth_disable_le_audio_hw_offload"
android:title="@string/bluetooth_disable_le_audio_hw_offload" />
<SwitchPreference
android:key="bluetooth_disable_a2dp_hw_offload"
android:title="@string/bluetooth_disable_a2dp_hw_offload" />
<ListPreference
android:key="bluetooth_select_avrcp_version"
android:title="@string/bluetooth_select_avrcp_version_string"

View File

@@ -53,7 +53,7 @@ public class BluetoothA2dpHwOffloadPreferenceController extends DeveloperOptions
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
BluetoothHwOffloadRebootDialog.show(mFragment);
BluetoothRebootDialog.show(mFragment);
mChanged = true;
return false;
}
@@ -93,9 +93,9 @@ public class BluetoothA2dpHwOffloadPreferenceController extends DeveloperOptions
}
/**
* Called when the HwOffloadDialog confirm is clicked.
* Called when the RebootDialog confirm is clicked.
*/
public void onHwOffloadDialogConfirmed() {
public void onRebootDialogConfirmed() {
if (!mChanged) {
return;
}
@@ -109,9 +109,9 @@ public class BluetoothA2dpHwOffloadPreferenceController extends DeveloperOptions
}
/**
* Called when the HwOffloadDialog cancel is clicked.
* Called when the RebootDialog cancel is clicked.
*/
public void onHwOffloadDialogCanceled() {
public void onRebootDialogCanceled() {
mChanged = false;
}
}

View File

@@ -18,6 +18,9 @@ package com.android.settings.development;
import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController.A2DP_OFFLOAD_SUPPORTED_PROPERTY;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.os.SystemProperties;
@@ -43,6 +46,9 @@ public class BluetoothLeAudioHwOffloadPreferenceController
static final String LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY =
"ro.bluetooth.leaudio_offload.supported";
@VisibleForTesting
BluetoothAdapter mBluetoothAdapter;
@VisibleForTesting
boolean mChanged = false;
@@ -50,6 +56,7 @@ public class BluetoothLeAudioHwOffloadPreferenceController
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
}
@Override
@@ -59,17 +66,24 @@ public class BluetoothLeAudioHwOffloadPreferenceController
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
BluetoothHwOffloadRebootDialog.show(mFragment);
BluetoothRebootDialog.show(mFragment);
mChanged = true;
return false;
}
@Override
public void updateState(Preference preference) {
if (mBluetoothAdapter == null) {
return;
}
final boolean leAudioEnabled =
(mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
final boolean offloadSupported =
SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false)
&& SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
if (offloadSupported) {
if (leAudioEnabled && offloadSupported) {
final boolean offloadDisabled =
SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, true);
((SwitchPreference) mPreference).setChecked(offloadDisabled);
@@ -82,12 +96,20 @@ public class BluetoothLeAudioHwOffloadPreferenceController
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
if (mBluetoothAdapter == null) {
return;
}
final boolean leAudioEnabled =
(mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
final boolean offloadSupported =
SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false)
&& SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
if (offloadSupported) {
if (leAudioEnabled && offloadSupported) {
((SwitchPreference) mPreference).setChecked(true);
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, "true");
} else {
mPreference.setEnabled(false);
}
}
@@ -104,9 +126,9 @@ public class BluetoothLeAudioHwOffloadPreferenceController
}
/**
* Called when the HwOffloadDialog confirm is clicked.
* Called when the RebootDialog confirm is clicked.
*/
public void onHwOffloadDialogConfirmed() {
public void onRebootDialogConfirmed() {
if (!mChanged) {
return;
}
@@ -119,9 +141,9 @@ public class BluetoothLeAudioHwOffloadPreferenceController
}
/**
* Called when the HwOffloadDialog cancel is clicked.
* Called when the RebootDialog cancel is clicked.
*/
public void onHwOffloadDialogCanceled() {
public void onRebootDialogCanceled() {
mChanged = false;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2022 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.BluetoothManager;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.os.SystemProperties;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
/**
* Preference controller to control Bluetooth LE audio feature
*/
public class BluetoothLeAudioPreferenceController
extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String PREFERENCE_KEY = "bluetooth_enable_leaudio";
private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
"ro.bluetooth.leaudio_switcher.supported";
@VisibleForTesting
static final String LE_AUDIO_DYNAMIC_ENABLED_PROPERTY =
"persist.bluetooth.leaudio_switcher.enabled";
private final DevelopmentSettingsDashboardFragment mFragment;
@VisibleForTesting
BluetoothAdapter mBluetoothAdapter;
@VisibleForTesting
boolean mChanged = false;
public BluetoothLeAudioPreferenceController(Context context,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
}
@Override
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
BluetoothRebootDialog.show(mFragment);
mChanged = true;
return false;
}
@Override
public void updateState(Preference preference) {
if (mBluetoothAdapter == null) {
return;
}
final boolean leAudioEnabled =
(mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
((SwitchPreference) mPreference).setChecked(leAudioEnabled);
final boolean leAudioSwitchSupported =
SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false);
if (!leAudioSwitchSupported) {
mPreference.setEnabled(false);
} else {
SystemProperties.set(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY,
Boolean.toString(leAudioEnabled));
}
}
/**
* Called when the RebootDialog confirm is clicked.
*/
public void onRebootDialogConfirmed() {
if (!mChanged || mBluetoothAdapter == null) {
return;
}
final boolean leAudioEnabled =
(mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
SystemProperties.set(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY,
Boolean.toString(!leAudioEnabled));
}
/**
* Called when the RebootDialog cancel is clicked.
*/
public void onRebootDialogCanceled() {
mChanged = false;
}
}

View File

@@ -29,22 +29,23 @@ import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/**
* The a2dp and LE audio offload switch should reboot the device to take effect, the dialog is
* to ask the user to reboot the device after a2dp or LE audio offload user preference changed
* The a2dp/LE audio offload and LE audio feature switch should reboot the device to take effect,
* the dialog is to ask the user to reboot the device after a2dp/LE audio offload and LE audio
* feature user preference changed
*/
public class BluetoothHwOffloadRebootDialog extends InstrumentedDialogFragment
public class BluetoothRebootDialog extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
public static final String TAG = "BluetoothHwOffloadReboot";
public static final String TAG = "BluetoothReboot";
/**
* The function to show the HwOffloadReboot Dialog.
* The function to show the Reboot Dialog.
*/
public static void show(DevelopmentSettingsDashboardFragment host) {
final FragmentManager manager = host.getActivity().getSupportFragmentManager();
if (manager.findFragmentByTag(TAG) == null) {
final BluetoothHwOffloadRebootDialog dialog =
new BluetoothHwOffloadRebootDialog();
final BluetoothRebootDialog dialog =
new BluetoothRebootDialog();
dialog.setTargetFragment(host, 0 /* requestCode */);
dialog.show(manager, TAG);
}
@@ -69,33 +70,33 @@ public class BluetoothHwOffloadRebootDialog extends InstrumentedDialogFragment
@Override
public void onClick(DialogInterface dialog, int which) {
final OnHwOffloadDialogListener host =
(OnHwOffloadDialogListener) getTargetFragment();
final OnRebootDialogListener host =
(OnRebootDialogListener) getTargetFragment();
if (host == null) {
return;
}
if (which == DialogInterface.BUTTON_POSITIVE) {
host.onHwOffloadDialogConfirmed();
host.onRebootDialogConfirmed();
PowerManager pm = getContext().getSystemService(PowerManager.class);
pm.reboot(null);
} else {
host.onHwOffloadDialogCanceled();
host.onRebootDialogCanceled();
}
}
/**
* The interface for the HsOffloadDialogListener to provide the action as the
* The interface for the RebootDialogListener to provide the action as the
* confirmed or canceled clicked.
*/
public interface OnHwOffloadDialogListener {
public interface OnRebootDialogListener {
/**
* Called when the user presses reboot on the warning dialog.
*/
void onHwOffloadDialogConfirmed();
void onRebootDialogConfirmed();
/**
* Called when the user presses cancel on the warning dialog.
*/
void onHwOffloadDialogCanceled();
void onRebootDialogCanceled();
}
}

View File

@@ -79,7 +79,7 @@ import java.util.List;
public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
implements OnMainSwitchChangeListener, OemUnlockDialogHost, AdbDialogHost,
AdbClearKeysDialogHost, LogPersistDialogHost,
BluetoothHwOffloadRebootDialog.OnHwOffloadDialogListener,
BluetoothRebootDialog.OnRebootDialogListener,
AbstractBluetoothPreferenceController.Callback {
private static final String TAG = "DevSettingsDashboard";
@@ -356,27 +356,37 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
}
@Override
public void onHwOffloadDialogConfirmed() {
public void onRebootDialogConfirmed() {
final BluetoothA2dpHwOffloadPreferenceController a2dpController =
getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class);
a2dpController.onHwOffloadDialogConfirmed();
a2dpController.onRebootDialogConfirmed();
final BluetoothLeAudioHwOffloadPreferenceController leAudioController =
getDevelopmentOptionsController(
BluetoothLeAudioHwOffloadPreferenceController.class);
leAudioController.onHwOffloadDialogConfirmed();
leAudioController.onRebootDialogConfirmed();
final BluetoothLeAudioPreferenceController leAudioFeatureController =
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogConfirmed();
}
@Override
public void onHwOffloadDialogCanceled() {
public void onRebootDialogCanceled() {
final BluetoothA2dpHwOffloadPreferenceController a2dpController =
getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class);
a2dpController.onHwOffloadDialogCanceled();
a2dpController.onRebootDialogCanceled();
final BluetoothLeAudioHwOffloadPreferenceController leAudioController =
getDevelopmentOptionsController(
BluetoothLeAudioHwOffloadPreferenceController.class);
leAudioController.onHwOffloadDialogCanceled();
leAudioController.onRebootDialogCanceled();
final BluetoothLeAudioPreferenceController leAudioFeatureController =
getDevelopmentOptionsController(
BluetoothLeAudioPreferenceController.class);
leAudioFeatureController.onRebootDialogCanceled();
}
@Override
@@ -533,6 +543,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new BluetoothAbsoluteVolumePreferenceController(context));
controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
controllers.add(new BluetoothMapVersionPreferenceController(context));
controllers.add(new BluetoothLeAudioPreferenceController(context, fragment));
controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));

View File

@@ -68,7 +68,7 @@ public class BluetoothA2dpHwOffloadPreferenceControllerTest {
SystemProperties.set(A2DP_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onHwOffloadDialogConfirmed();
mController.onRebootDialogConfirmed();
final boolean mode = SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(mode).isTrue();
}
@@ -80,7 +80,7 @@ public class BluetoothA2dpHwOffloadPreferenceControllerTest {
mController.mChanged = true;
mController.onHwOffloadDialogConfirmed();
mController.onRebootDialogConfirmed();
final boolean a2dpMode = SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, true);
final boolean leAudioMode = SystemProperties
.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, true);
@@ -93,7 +93,7 @@ public class BluetoothA2dpHwOffloadPreferenceControllerTest {
SystemProperties.set(A2DP_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onHwOffloadDialogCanceled();
mController.onRebootDialogCanceled();
final boolean mode = SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(mode).isFalse();
}

View File

@@ -66,7 +66,7 @@ public class BluetoothLeAudioHwOffloadPreferenceControllerTest {
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onHwOffloadDialogConfirmed();
mController.onRebootDialogConfirmed();
final boolean mode = SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(mode).isTrue();
}
@@ -76,7 +76,7 @@ public class BluetoothLeAudioHwOffloadPreferenceControllerTest {
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(true));
mController.mChanged = true;
mController.onHwOffloadDialogConfirmed();
mController.onRebootDialogConfirmed();
final boolean mode2 = SystemProperties.getBoolean(
LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, true);
assertThat(mode2).isFalse();
@@ -87,7 +87,7 @@ public class BluetoothLeAudioHwOffloadPreferenceControllerTest {
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(false));
mController.mChanged = true;
mController.onHwOffloadDialogCanceled();
mController.onRebootDialogCanceled();
final boolean mode = SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(mode).isFalse();
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2022 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 static com.android.settings.development.BluetoothLeAudioPreferenceController
.LE_AUDIO_DYNAMIC_ENABLED_PROPERTY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.os.SystemProperties;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BluetoothLeAudioPreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
@Mock
private BluetoothAdapter mBluetoothAdapter;
private Context mContext;
private SwitchPreference mPreference;
private BluetoothLeAudioPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPreference = new SwitchPreference(mContext);
mController = spy(new BluetoothLeAudioPreferenceController(mContext, mFragment));
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.mBluetoothAdapter = mBluetoothAdapter;
mController.displayPreference(mPreferenceScreen);
}
@Test
public void onRebootDialogConfirmedAsLeAudioDisabled_shouldSwitchStatus() {
when(mBluetoothAdapter.isLeAudioSupported())
.thenReturn(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mController.mChanged = true;
mController.onRebootDialogConfirmed();
final boolean status = SystemProperties
.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false);
assertThat(status).isTrue();
}
@Test
public void onRebootDialogConfirmedAsLeAudioEnabled_shouldSwitchStatus() {
when(mBluetoothAdapter.isLeAudioSupported())
.thenReturn(BluetoothStatusCodes.FEATURE_SUPPORTED);
mController.mChanged = true;
mController.onRebootDialogConfirmed();
final boolean status = SystemProperties
.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false);
assertThat(status).isFalse();
}
@Test
public void onRebootDialogCanceled_shouldNotSwitchStatus() {
when(mBluetoothAdapter.isLeAudioSupported())
.thenReturn(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mController.mChanged = true;
mController.onRebootDialogCanceled();
final boolean status = SystemProperties
.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false);
assertThat(status).isFalse();
}
}