Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e308853 authored by tim peng's avatar tim peng Committed by Android (Google) Code Review
Browse files

Merge "Add new HD audio preference controller for Bluetooth developer option"

parents 60b7c235 bea3a6e6
Loading
Loading
Loading
Loading
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.bluetooth;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.Log;

import androidx.preference.Preference;
import androidx.preference.SwitchPreference;

import com.android.settings.development.BluetoothA2dpConfigStore;
import com.android.settingslib.core.lifecycle.Lifecycle;

/**
 * Switch preference controller for HD audio(optional codec)
 */
public class BluetoothHDAudioPreferenceController extends AbstractBluetoothPreferenceController
        implements Preference.OnPreferenceChangeListener {

    private static final String KEY = "bluetooth_hd_audio_settings";
    private static final String TAG = "BtHDAudioCtr";

    private final Callback mCallback;

    public BluetoothHDAudioPreferenceController(Context context, Lifecycle lifecycle,
                                                BluetoothA2dpConfigStore store,
                                                Callback callback) {
        super(context, lifecycle, store);
        mCallback = callback;
    }

    @Override
    public void updateState(Preference preference) {
        final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
        if (bluetoothA2dp == null) {
            mPreference.setEnabled(false);
            return;
        }
        final BluetoothDevice activeDevice = bluetoothA2dp.getActiveDevice();
        if (activeDevice == null) {
            Log.e(TAG, "Active device is null. To disable HD audio button");
            mPreference.setEnabled(false);
            return;
        }
        final boolean supported = (bluetoothA2dp.supportsOptionalCodecs(activeDevice)
                == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
        mPreference.setEnabled(supported);
        if (supported) {
            final boolean isEnabled = bluetoothA2dp.getOptionalCodecsEnabled(activeDevice)
                    == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED;
            ((SwitchPreference) mPreference).setChecked(isEnabled);
        }
    }

    @Override
    public String getPreferenceKey() {
        return KEY;
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
        if (bluetoothA2dp == null) {
            mPreference.setEnabled(false);
            return true;
        }
        final boolean enabled = (Boolean) newValue;
        final int prefValue = enabled
                ? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
                : BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
        bluetoothA2dp.setOptionalCodecsEnabled(bluetoothA2dp.getActiveDevice(), prefValue);
        if (enabled) {
            bluetoothA2dp.enableOptionalCodecs(null); // Use current active device
        } else {
            bluetoothA2dp.disableOptionalCodecs(null); // Use current active device
        }
        mCallback.onBluetoothHDAudioEnabled(enabled);
        return true;
    }
}
+164 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.bluetooth;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.content.Context;

import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;

import com.android.settings.development.BluetoothA2dpConfigStore;
import com.android.settingslib.core.lifecycle.Lifecycle;

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;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowBluetoothDevice;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothDevice.class})
public class BluetoothHDAudioPreferenceControllerTest {

    private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";

    @Mock
    private BluetoothA2dp mBluetoothA2dp;
    @Mock
    private PreferenceScreen mScreen;
    @Mock
    private AbstractBluetoothPreferenceController.Callback mCallback;

    private BluetoothHDAudioPreferenceController mController;
    private SwitchPreference mPreference;
    private BluetoothA2dpConfigStore mBluetoothA2dpConfigStore;
    private Context mContext;
    private LifecycleOwner mLifecycleOwner;
    private Lifecycle mLifecycle;
    private BluetoothDevice mActiveDevice;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mContext = RuntimeEnvironment.application;
        mLifecycleOwner = () -> mLifecycle;
        mLifecycle = new Lifecycle(mLifecycleOwner);
        mBluetoothA2dpConfigStore = spy(new BluetoothA2dpConfigStore());
        mController = new BluetoothHDAudioPreferenceController(mContext, mLifecycle,
                mBluetoothA2dpConfigStore, mCallback);
        mPreference = new SwitchPreference(mContext);
        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
        mController.displayPreference(mScreen);
        mActiveDevice = ShadowBluetoothDevice.newInstance(TEST_DEVICE_ADDRESS);
    }

    @Test
    public void updateState_noActiveDevice_setDisable() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(null);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        mController.updateState(mPreference);

        assertThat(mPreference.isEnabled()).isFalse();
    }

    @Test
    public void updateState_codecSupported_setEnable() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        when(mBluetoothA2dp.supportsOptionalCodecs(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        mController.updateState(mPreference);

        assertThat(mPreference.isEnabled()).isTrue();
    }

    @Test
    public void updateState_codecNotSupported_setDisable() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        when(mBluetoothA2dp.supportsOptionalCodecs(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        mController.updateState(mPreference);

        assertThat(mPreference.isEnabled()).isFalse();
    }

    @Test
    public void updateState_codecSupportedAndEnabled_checked() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        when(mBluetoothA2dp.supportsOptionalCodecs(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
        when(mBluetoothA2dp.getOptionalCodecsEnabled(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        mController.updateState(mPreference);

        assertThat(mPreference.isChecked()).isTrue();
    }

    @Test
    public void updateState_codecSupportedAndDisabled_notChecked() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        when(mBluetoothA2dp.supportsOptionalCodecs(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
        when(mBluetoothA2dp.getOptionalCodecsEnabled(mActiveDevice)).thenReturn(
                mBluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        mController.updateState(mPreference);

        assertThat(mPreference.isChecked()).isFalse();
    }

    @Test
    public void onPreferenceChange_disable_verifyFlow() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        final boolean enabled = false;
        mController.onPreferenceChange(mPreference, enabled);

        verify(mBluetoothA2dp).disableOptionalCodecs(null);
        verify(mBluetoothA2dp).setOptionalCodecsEnabled(mActiveDevice,
                BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
        verify(mCallback).onBluetoothHDAudioEnabled(enabled);
    }

    @Test
    public void onPreferenceChange_enable_verifyFlow() {
        when(mBluetoothA2dp.getActiveDevice()).thenReturn(mActiveDevice);
        mController.onBluetoothServiceConnected(mBluetoothA2dp);
        final boolean enabled = true;
        mController.onPreferenceChange(mPreference, enabled);

        verify(mBluetoothA2dp).enableOptionalCodecs(null);
        verify(mBluetoothA2dp).setOptionalCodecsEnabled(mActiveDevice,
                BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
        verify(mCallback).onBluetoothHDAudioEnabled(enabled);
    }
}