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

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

Merge "Move bluetooth operations inAdvancedBluetoothDetailHeader to background thread" into main

parents 6749a92c 1f09fa5d
Loading
Loading
Loading
Loading
+169 −73
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.bluetooth;

import static com.android.settings.bluetooth.Utils.preloadAndRun;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ContentResolver;
@@ -55,9 +57,13 @@ import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.LayoutPreference;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -236,24 +242,42 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
    @VisibleForTesting
    void refresh() {
        if (mLayoutPreference != null && mCachedDevice != null) {
            final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
            title.setText(mCachedDevice.getName());
            final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);

            if (!mCachedDevice.isConnected() || mCachedDevice.isBusy()) {
                summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
            Supplier<String> deviceName = Suppliers.memoize(() -> mCachedDevice.getName());
            Supplier<Boolean> disconnected =
                    Suppliers.memoize(() -> !mCachedDevice.isConnected() || mCachedDevice.isBusy());
            Supplier<Boolean> isUntetheredHeadset =
                    Suppliers.memoize(() -> isUntetheredHeadset(mCachedDevice.getDevice()));
            Supplier<String> summaryText =
                    Suppliers.memoize(
                            () -> {
                                if (disconnected.get() || isUntetheredHeadset.get()) {
                                    return mCachedDevice.getConnectionSummary(
                                            /* shortSummary= */ true);
                                }
                                return mCachedDevice.getConnectionSummary(
                                        BluetoothUtils.getIntMetaData(
                                                        mCachedDevice.getDevice(),
                                                        BluetoothDevice.METADATA_MAIN_BATTERY)
                                                != BluetoothUtils.META_INT_ERROR);
                            });
            preloadAndRun(
                    List.of(deviceName, disconnected, isUntetheredHeadset, summaryText),
                    () -> {
                        final TextView title =
                                mLayoutPreference.findViewById(R.id.entity_header_title);
                        title.setText(deviceName.get());
                        final TextView summary =
                                mLayoutPreference.findViewById(R.id.entity_header_summary);

                        if (disconnected.get()) {
                            summary.setText(summaryText.get());
                            updateDisconnectLayout();
                            return;
                        }
            final BluetoothDevice device = mCachedDevice.getDevice();
            final String deviceType = BluetoothUtils.getStringMetaData(device,
                    BluetoothDevice.METADATA_DEVICE_TYPE);
            if (TextUtils.equals(deviceType,
                    BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)
                    || BluetoothUtils.getBooleanMetaData(device,
                    BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
                summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left),
                        if (isUntetheredHeadset.get()) {
                            summary.setText(summaryText.get());
                            updateSubLayout(
                                    mLayoutPreference.findViewById(R.id.layout_left),
                                    BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON,
                                    BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY,
                                    BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
@@ -261,7 +285,8 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
                                    R.string.bluetooth_left_name,
                                    LEFT_DEVICE_ID);

                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
                            updateSubLayout(
                                    mLayoutPreference.findViewById(R.id.layout_middle),
                                    BluetoothDevice.METADATA_UNTETHERED_CASE_ICON,
                                    BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY,
                                    BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
@@ -269,7 +294,8 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
                                    R.string.bluetooth_middle_name,
                                    CASE_DEVICE_ID);

                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
                            updateSubLayout(
                                    mLayoutPreference.findViewById(R.id.layout_right),
                                    BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON,
                                    BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY,
                                    BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
@@ -279,20 +305,24 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont

                            showBothDevicesBatteryPredictionIfNecessary();
                        } else {
                mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
                mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);

                summary.setText(mCachedDevice.getConnectionSummary(
                        BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
                                != BluetoothUtils.META_INT_ERROR));
                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
                            mLayoutPreference
                                    .findViewById(R.id.layout_left)
                                    .setVisibility(View.GONE);
                            mLayoutPreference
                                    .findViewById(R.id.layout_right)
                                    .setVisibility(View.GONE);

                            summary.setText(summaryText.get());
                            updateSubLayout(
                                    mLayoutPreference.findViewById(R.id.layout_middle),
                                    BluetoothDevice.METADATA_MAIN_ICON,
                                    BluetoothDevice.METADATA_MAIN_BATTERY,
                                    BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
                                    BluetoothDevice.METADATA_MAIN_CHARGING,
                        /* titleResId */ 0,
                                    /* titleResId= */ 0,
                                    MAIN_DEVICE_ID);
                        }
                    });
        }
    }

@@ -315,13 +345,87 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
        return drawable;
    }

    private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey,
            int lowBatteryMetaKey, int chargeMetaKey, int titleResId, int deviceId) {
    private void updateSubLayout(
            LinearLayout linearLayout,
            int iconMetaKey,
            int batteryMetaKey,
            int lowBatteryMetaKey,
            int chargeMetaKey,
            int titleResId,
            int deviceId) {
        if (linearLayout == null) {
            return;
        }
        BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
        Supplier<String> iconUri =
                Suppliers.memoize(
                        () -> BluetoothUtils.getStringMetaData(bluetoothDevice, iconMetaKey));
        Supplier<Integer> batteryLevel =
                Suppliers.memoize(
                        () -> BluetoothUtils.getIntMetaData(bluetoothDevice, batteryMetaKey));
        Supplier<Boolean> charging =
                Suppliers.memoize(
                        () -> BluetoothUtils.getBooleanMetaData(bluetoothDevice, chargeMetaKey));
        Supplier<Integer> lowBatteryLevel =
                Suppliers.memoize(
                        () -> {
                            int level =
                                    BluetoothUtils.getIntMetaData(
                                            bluetoothDevice, lowBatteryMetaKey);
                            if (level == BluetoothUtils.META_INT_ERROR) {
                                if (batteryMetaKey
                                        == BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY) {
                                    level = CASE_LOW_BATTERY_LEVEL;
                                } else {
                                    level = LOW_BATTERY_LEVEL;
                                }
                            }
                            return level;
                        });
        Supplier<Boolean> isUntethered =
                Suppliers.memoize(() -> isUntetheredHeadset(bluetoothDevice));
        Supplier<Integer> nativeBatteryLevel = Suppliers.memoize(bluetoothDevice::getBatteryLevel);
        preloadAndRun(
                List.of(
                        iconUri,
                        batteryLevel,
                        charging,
                        lowBatteryLevel,
                        isUntethered,
                        nativeBatteryLevel),
                () ->
                        updateSubLayoutUi(
                                linearLayout,
                                iconMetaKey,
                                batteryMetaKey,
                                lowBatteryMetaKey,
                                chargeMetaKey,
                                titleResId,
                                deviceId,
                                iconUri,
                                batteryLevel,
                                charging,
                                lowBatteryLevel,
                                isUntethered,
                                nativeBatteryLevel));
    }

    private void updateSubLayoutUi(
            LinearLayout linearLayout,
            int iconMetaKey,
            int batteryMetaKey,
            int lowBatteryMetaKey,
            int chargeMetaKey,
            int titleResId,
            int deviceId,
            Supplier<String> preloadedIconUri,
            Supplier<Integer> preloadedBatteryLevel,
            Supplier<Boolean> preloadedCharging,
            Supplier<Integer> preloadedLowBatteryLevel,
            Supplier<Boolean> preloadedIsUntethered,
            Supplier<Integer> preloadedNativeBatteryLevel) {
        final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
        final String iconUri = BluetoothUtils.getStringMetaData(bluetoothDevice, iconMetaKey);
        final String iconUri = preloadedIconUri.get();
        final ImageView imageView = linearLayout.findViewById(R.id.header_icon);
        if (iconUri != null) {
            updateIcon(imageView, iconUri);
@@ -331,17 +435,9 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
            imageView.setImageDrawable(pair.first);
            imageView.setContentDescription(pair.second);
        }
        final int batteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice, batteryMetaKey);
        final boolean charging = BluetoothUtils.getBooleanMetaData(bluetoothDevice, chargeMetaKey);
        int lowBatteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice,
                lowBatteryMetaKey);
        if (lowBatteryLevel == BluetoothUtils.META_INT_ERROR) {
            if (batteryMetaKey == BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY) {
                lowBatteryLevel = CASE_LOW_BATTERY_LEVEL;
            } else {
                lowBatteryLevel = LOW_BATTERY_LEVEL;
            }
        }
        final int batteryLevel = preloadedBatteryLevel.get();
        final boolean charging = preloadedCharging.get();
        int lowBatteryLevel = preloadedLowBatteryLevel.get();

        Log.d(TAG, "buletoothDevice: " + bluetoothDevice.getAnonymizedAddress()
                + ", updateSubLayout() icon : " + iconMetaKey + ", battery : " + batteryMetaKey
@@ -353,7 +449,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
            showBatteryPredictionIfNecessary(linearLayout, deviceId, batteryLevel);
        }
        final TextView batterySummaryView = linearLayout.findViewById(R.id.bt_battery_summary);
        if (isUntetheredHeadset(bluetoothDevice)) {
        if (preloadedIsUntethered.get()) {
            if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
                linearLayout.setVisibility(View.VISIBLE);
                batterySummaryView.setText(
@@ -364,7 +460,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
                if (deviceId == MAIN_DEVICE_ID) {
                    linearLayout.setVisibility(View.VISIBLE);
                    linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE);
                    int level = bluetoothDevice.getBatteryLevel();
                    int level = preloadedNativeBatteryLevel.get();
                    if (level != BluetoothDevice.BATTERY_LEVEL_UNKNOWN
                            && level != BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF) {
                        batterySummaryView.setText(
+22 −0
Original line number Diff line number Diff line
@@ -37,12 +37,16 @@ import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;

import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
import com.android.settingslib.utils.ThreadUtils;

import com.google.common.base.Supplier;

import java.util.ArrayList;
import java.util.List;
@@ -272,4 +276,22 @@ public final class Utils {
                + " , deviceList = " + cachedBluetoothDevices);
        return cachedBluetoothDevices;
    }

    /**
     * Preloads the values and run the Runnable afterwards.
     * @param suppliers the value supplier, should be a memoized supplier
     * @param runnable the runnable to be run after value is preloaded
     */
    public static void preloadAndRun(List<Supplier<?>> suppliers, Runnable runnable) {
        if (!Flags.enableOffloadBluetoothOperationsToBackgroundThread()) {
            runnable.run();
            return;
        }
        ThreadUtils.postOnBackgroundThread(() -> {
            for (Supplier<?> supplier : suppliers) {
                supplier.get();
            }
            ThreadUtils.postOnMainThread(runnable);
        });
    }
}