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

Commit 4c4c978d authored by Haijie Hong's avatar Haijie Hong Committed by Android (Google) Code Review
Browse files

Merge "Clean up BluetoothDetailsHeaderController" into main

parents b4998320 dca3dc8e
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -26,13 +26,6 @@
        settings:allowDividerBelow="true"
        settings:searchable="false"/>

    <com.android.settingslib.widget.LayoutPreference
        android:key="bluetooth_device_header"
        android:layout="@layout/settings_entity_header"
        android:selectable="false"
        settings:allowDividerBelow="true"
        settings:searchable="false"/>

    <com.android.settingslib.widget.LayoutPreference
        android:key="general_bluetooth_device_header"
        android:layout="@layout/general_bt_entity_header"
+0 −94
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.bluetooth;

import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.Pair;

import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.LayoutPreference;

/**
 * This class adds a header with device name and status (connected/disconnected, etc.).
 */
public class BluetoothDetailsHeaderController extends BluetoothDetailsController {
    private static final String KEY_DEVICE_HEADER = "bluetooth_device_header";

    private EntityHeaderController mHeaderController;

    public BluetoothDetailsHeaderController(Context context, PreferenceFragmentCompat fragment,
            CachedBluetoothDevice device, Lifecycle lifecycle) {
        super(context, fragment, device, lifecycle);
    }

    @Override
    public boolean isAvailable() {
        if (Flags.enableBluetoothDeviceDetailsPolish()) {
            return false;
        }
        boolean hasLeAudio = mCachedDevice.getUiAccessibleProfiles()
                .stream()
                .anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
        return !BluetoothUtils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && !hasLeAudio;
    }

    @Override
    protected void init(PreferenceScreen screen) {
        final LayoutPreference headerPreference = screen.findPreference(KEY_DEVICE_HEADER);
        mHeaderController = EntityHeaderController.newInstance(mFragment.getActivity(), mFragment,
                headerPreference.findViewById(R.id.entity_header));
    }

    protected void setHeaderProperties() {
        final Pair<Drawable, String> pair =
                BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
        String summaryText = mCachedDevice.getConnectionSummary();
        if (TextUtils.isEmpty(summaryText)) {
            // If first summary is unavailable, not to show second summary.
            mHeaderController.setSecondSummary((CharSequence)null);
        }

        mHeaderController.setLabel(mCachedDevice.getName());
        mHeaderController.setIcon(pair.first);
        mHeaderController.setIconContentDescription(pair.second);
        mHeaderController.setSummary(summaryText);
    }

    @Override
    protected void refresh() {
        if (isAvailable()) {
            setHeaderProperties();
            mHeaderController.done(true /* rebindActions */);
        }
    }

    @Override
    public String getPreferenceKey() {
        return KEY_DEVICE_HEADER;
    }
}
 No newline at end of file
+0 −7
Original line number Diff line number Diff line
@@ -260,9 +260,6 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable
        getController(
                AdvancedBluetoothDetailsHeaderController.class,
                controller -> controller.displayPreference(getPreferenceScreen()));
        getController(
                BluetoothDetailsHeaderController.class,
                controller -> controller.displayPreference(getPreferenceScreen()));
    }

    protected <T extends AbstractPreferenceController> void getController(Class<T> clazz,
@@ -376,7 +373,6 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable
        visibleKeys
                .add(use(BluetoothDetailsBannerController.class).getPreferenceKey())
                .add(use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(BluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(BluetoothDetailsButtonsController.class).getPreferenceKey());
        if (!BluetoothUtils.isHeadset(cachedDevice.getDevice())) {
@@ -390,7 +386,6 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable
        visibleKeys
                .add(use(BluetoothDetailsBannerController.class).getPreferenceKey())
                .add(use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(BluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey())
                .add(use(BluetoothDetailsButtonsController.class).getPreferenceKey())
                .add(LOADING_PREF);
@@ -405,8 +400,6 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable
            controllers.add(
                    new BluetoothDetailsBannerController(
                            context, this, cachedDevice, lifecycle));
            controllers.add(new BluetoothDetailsHeaderController(context, this, cachedDevice,
                    lifecycle));
            controllers.add(
                    new GeneralBluetoothDetailsHeaderController(
                            context, this, cachedDevice, lifecycle));
+0 −135
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.bluetooth;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothDevice;
import android.graphics.drawable.Drawable;

import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.widget.LayoutPreference;

import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Ignore
@Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class})
public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsControllerTestBase {

    private BluetoothDetailsHeaderController mController;
    private LayoutPreference mPreference;

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private EntityHeaderController mHeaderController;
    @Mock
    private LocalBluetoothManager mBluetoothManager;
    @Mock
    private CachedBluetoothDeviceManager mCachedDeviceManager;
    @Mock
    private BluetoothDevice mBluetoothDevice;

    @Override
    public void setUp() {
        super.setUp();
        FakeFeatureFactory.setupForTest();
        ShadowEntityHeaderController.setUseMock(mHeaderController);
        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
        when(mCachedDeviceManager.getSubDeviceSummary(mCachedDevice)).thenReturn("abc");
        mController =
            new BluetoothDetailsHeaderController(mContext, mFragment, mCachedDevice, mLifecycle);
        mPreference = new LayoutPreference(
                mContext, com.android.settingslib.widget.preference.layout.R.layout.settings_entity_header);
        mPreference.setKey(mController.getPreferenceKey());
        mScreen.addPreference(mPreference);
        setupDevice(mDeviceConfig);
        when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
    }

    @After
    public void tearDown() {
        ShadowEntityHeaderController.reset();
    }

    /**
     * Test to verify the current test context object works so that we are not checking null
     * against null
     */
    @Test
    public void testContextMock() {
        assertThat(mContext.getString(com.android.settingslib.R.string.bluetooth_connected))
                .isNotNull();
    }

    @Test
    public void header() {
        showScreen(mController);

        verify(mHeaderController).setLabel(mDeviceConfig.getName());
        verify(mHeaderController).setIcon(any(Drawable.class));
        verify(mHeaderController).setIconContentDescription(any(String.class));
        verify(mHeaderController).setSummary(any(String.class));
        verify(mHeaderController).setSecondSummary(any(String.class));
        verify(mHeaderController).done(true);
    }

    @Test
    public void connectionStatusChangesWhileScreenOpen() {
        InOrder inOrder = inOrder(mHeaderController);
        when(mCachedDevice.getConnectionSummary())
            .thenReturn(mContext.getString(com.android.settingslib.R.string.bluetooth_connected));
        showScreen(mController);
        inOrder.verify(mHeaderController)
            .setSummary(mContext.getString(com.android.settingslib.R.string.bluetooth_connected));

        when(mCachedDevice.getConnectionSummary()).thenReturn(null);
        mController.onDeviceAttributesChanged();
        inOrder.verify(mHeaderController).setSummary((CharSequence) null);

        when(mCachedDevice.getConnectionSummary())
            .thenReturn(mContext.getString(com.android.settingslib.R.string.bluetooth_connecting));
        mController.onDeviceAttributesChanged();
        inOrder.verify(mHeaderController)
            .setSummary(mContext.getString(com.android.settingslib.R.string.bluetooth_connecting));
    }

    @Test
    public void isAvailable_untetheredHeadset_returnFalse() {
        when(mBluetoothDevice.getMetadata(
                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn("true".getBytes());

        assertThat(mController.isAvailable()).isFalse();
    }
}