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

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

Merge "Add base preference for new Bluetooth developer option"

parents feb51e20 fdd98bd9
Loading
Loading
Loading
Loading
+171 −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.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;

import com.android.settings.R;
import com.android.settingslib.CustomDialogPreferenceCompat;

import java.util.ArrayList;
import java.util.List;

/**
 * Abstract class for Bluetooth A2DP config preference in developer option.
 */
public abstract class BaseBluetoothDialogPreference extends CustomDialogPreferenceCompat implements
        RadioGroup.OnCheckedChangeListener{
    private static final String TAG = "BaseBluetoothDlgPref";

    protected List<Integer> mRadioButtonIds = new ArrayList<>();
    protected List<String> mRadioButtonStrings = new ArrayList<>();
    protected List<String> mSummaryStrings = new ArrayList<>();

    private Callback mCallback;

    public BaseBluetoothDialogPreference(Context context) {
        super(context);
    }

    public BaseBluetoothDialogPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BaseBluetoothDialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public BaseBluetoothDialogPreference(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);
        if (mCallback == null) {
            Log.e(TAG, "Unable to show dialog by the callback is null");
            return;
        }
        if (mRadioButtonStrings.size() != mRadioButtonIds.size()) {
            Log.e(TAG, "Unable to show dialog by the view and string size are not matched");
            return;
        }
        final int currentIndex = mCallback.getCurrentConfigIndex();
        if (currentIndex < 0 || currentIndex >= mRadioButtonIds.size()) {
            Log.e(TAG, "Unable to show dialog by the incorrect index: " + currentIndex);
            return;
        }
        // Initial radio button group
        final RadioGroup radioGroup = view.findViewById(getRadioButtonGroupId());
        if (radioGroup == null) {
            Log.e(TAG, "Unable to show dialog by no radio button group: "
                    + getRadioButtonGroupId());
            return;
        }
        radioGroup.check(mRadioButtonIds.get(currentIndex));
        radioGroup.setOnCheckedChangeListener(this);
        // Initial radio button
        final List<Integer> selectableIndex = mCallback.getSelectableIndex();
        RadioButton radioButton;
        for (int i = 0; i < mRadioButtonStrings.size(); i++) {
            radioButton = view.findViewById(mRadioButtonIds.get(i));
            if (radioButton == null) {
                Log.e(TAG, "Unable to show dialog by no radio button:" + mRadioButtonIds.get(i));
                return;
            }
            radioButton.setText(mRadioButtonStrings.get(i));
            radioButton.setEnabled(selectableIndex.contains(i));
        }
        // View will be invisible when all options are enabled.
        if (selectableIndex.size() == mRadioButtonIds.size()) {
            final TextView helpTextView = view.findViewById(R.id.bluetooth_audio_codec_help_info);
            helpTextView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (mCallback == null) {
            Log.e(TAG, "Callback is null");
            return;
        }
        mCallback.onIndexUpdated(mRadioButtonIds.indexOf(checkedId));
        getDialog().dismiss();
    }

    /**
     * Method to set callback.
     */
    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    /**
     * Method to get summary strings by index.
     */
    protected String generateSummary(int index) {
        if (index > mSummaryStrings.size()) {
            Log.e(TAG, "Unable to get summary of " + index + ". Size is " + mSummaryStrings.size());
            return null;
        }
        return index == getDefaultIndex() ? mSummaryStrings.get(getDefaultIndex()) :
                String.format(getContext().getResources().getString(
                        R.string.bluetooth_select_a2dp_codec_streaming_label),
                        mSummaryStrings.get(index));
    }

    /**
     * Method to get default index.
     */
    protected int getDefaultIndex() {
        return 0;
    }

    /**
     * Method to get radio button group id.
     */
    protected abstract int getRadioButtonGroupId();

    /**
     * Callback interface for this class to manipulate data from controller.
     */
    public interface Callback {
        /**
         * Method to get current Bluetooth A2DP config index.
         */
        int getCurrentConfigIndex();
        /**
         * Method to get selectable config index which means supported by phone and device.
         *
         * @return the available {@link List} of the Bluetooth A2DP config.
         */
        List<Integer> getSelectableIndex();
        /**
         * Method to notify controller when user changes config.
         *
         * @param index for the selected index.
         */
        void onIndexUpdated(int index);
    }
}
+189 −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.app.Dialog;
import android.content.Context;
import android.view.View;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;

import com.android.settings.R;

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 java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
public class BaseBluetoothDialogPreferenceTest {

    private static final int ID1 = 99;
    private static final int ID2 = 100;
    private static final int RADIOGROUP_ID = 101;
    private static final int TEXT_VIEW_ID = R.id.bluetooth_audio_codec_help_info;
    private static final String BUTTON1 = "Test button1";
    private static final String BUTTON2 = "Test button2";
    private static final String SUMMARY1 = "Test summary1";
    private static final String SUMMARY2 = "Test summary2";

    @Mock
    private BaseBluetoothDialogPreference.Callback mCallback;
    @Mock
    private Dialog mDialog;
    @Mock
    private View mView;

    private BaseBluetoothDialogPreference mPreference;
    private Context mContext;
    private RadioButton mRadioButton1;
    private RadioButton mRadioButton2;
    private RadioGroup mRadioGroup;
    private TextView mTextView;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mContext = RuntimeEnvironment.application;
        mPreference = spy(new BaseBluetoothDialogPreferenceImpl(mContext));
        mRadioButton1 = new RadioButton(mContext);
        mRadioButton1.setId(ID1);
        mRadioButton2 = new RadioButton(mContext);
        mRadioButton2.setId(ID2);
        mRadioGroup = new RadioGroup(mContext);
        mRadioGroup.addView(mRadioButton1);
        mRadioGroup.addView(mRadioButton2);
        mTextView = new TextView(mContext);
        mPreference.mRadioButtonIds.add(ID1);
        mPreference.mRadioButtonIds.add(ID2);
        mPreference.mRadioButtonStrings.add(BUTTON1);
        mPreference.mRadioButtonStrings.add(BUTTON2);
        mPreference.mSummaryStrings.add(SUMMARY1);
        mPreference.mSummaryStrings.add(SUMMARY2);
        mPreference.setCallback(mCallback);
        when(mView.findViewById(mPreference.getRadioButtonGroupId())).thenReturn(mRadioGroup);
    }

    @Test
    public void onBindDialogView_checkRadioButtonsSelection() {
        when(mCallback.getCurrentConfigIndex()).thenReturn(1);

        assertThat(mRadioGroup.getCheckedRadioButtonId()).isNotEqualTo(ID2);
        mPreference.onBindDialogView(mView);

        assertThat(mRadioGroup.getCheckedRadioButtonId()).isEqualTo(ID2);
    }

    @Test
    public void onBindDialogView_checkRadioButtonsText() {
        when(mView.findViewById(ID1)).thenReturn(mRadioButton1);
        when(mView.findViewById(ID2)).thenReturn(mRadioButton2);

        assertThat(mRadioButton1.getText()).isNotEqualTo(BUTTON1);
        assertThat(mRadioButton2.getText()).isNotEqualTo(BUTTON2);
        mPreference.onBindDialogView(mView);

        assertThat(mRadioButton1.getText()).isEqualTo(BUTTON1);
        assertThat(mRadioButton2.getText()).isEqualTo(BUTTON2);
    }

    @Test
    public void onBindDialogView_checkRadioButtonsState() {
        when(mView.findViewById(ID1)).thenReturn(mRadioButton1);
        when(mView.findViewById(ID2)).thenReturn(mRadioButton2);
        List<Integer> indexes = new ArrayList<>();
        indexes.add(0);
        when(mCallback.getSelectableIndex()).thenReturn(indexes);

        assertThat(mRadioButton1.isEnabled()).isTrue();
        assertThat(mRadioButton2.isEnabled()).isTrue();
        mPreference.onBindDialogView(mView);

        assertThat(mRadioButton1.isEnabled()).isTrue();
        assertThat(mRadioButton2.isEnabled()).isFalse();
    }

    @Test
    public void onBindDialogView_allButtonsEnabled_hideHelpText() {
        when(mView.findViewById(ID1)).thenReturn(mRadioButton1);
        when(mView.findViewById(ID2)).thenReturn(mRadioButton2);
        when(mView.findViewById(TEXT_VIEW_ID)).thenReturn(mTextView);
        List<Integer> indexes = new ArrayList<>();
        indexes.add(0);
        indexes.add(1);
        when(mCallback.getSelectableIndex()).thenReturn(indexes);

        assertThat(mTextView.getVisibility()).isEqualTo(View.VISIBLE);
        mPreference.onBindDialogView(mView);
        assertThat(mTextView.getVisibility()).isEqualTo(View.GONE);
    }

    @Test
    public void onBindDialogView_buttonDisabled_showHelpText() {
        when(mView.findViewById(ID1)).thenReturn(mRadioButton1);
        when(mView.findViewById(ID2)).thenReturn(mRadioButton2);
        when(mView.findViewById(TEXT_VIEW_ID)).thenReturn(mTextView);
        List<Integer> indexes = new ArrayList<>();
        indexes.add(0);
        when(mCallback.getSelectableIndex()).thenReturn(indexes);

        mPreference.onBindDialogView(mView);
        assertThat(mTextView.getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test
    public void onCheckedChanged_verifyIndex() {
        when(mPreference.getDialog()).thenReturn(mDialog);

        mPreference.onCheckedChanged(mRadioGroup, ID2);
        verify(mCallback).onIndexUpdated(1);
    }

    @Test
    public void generateSummary_checkString() {
        final String summary = String.format(mContext.getResources().getString(
                R.string.bluetooth_select_a2dp_codec_streaming_label), SUMMARY2);

        assertThat(mPreference.generateSummary(1)).isEqualTo(summary);
    }


    private static class BaseBluetoothDialogPreferenceImpl extends BaseBluetoothDialogPreference {

        private BaseBluetoothDialogPreferenceImpl(Context context) {
            super(context);
        }

        @Override
        protected int getRadioButtonGroupId() {
            return RADIOGROUP_ID;
        }
    }
}