Move bluetooth operations inAdvancedBluetoothDetailHeader to background thread
Bug: 305636727 Test: atest AdvancedBluetoothDetailsHeaderControllerTest Change-Id: I2827deb7ab989169eb2c64c8d075e18cd1a307c7
This commit is contained in:
@@ -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,63 +242,87 @@ 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);
|
||||
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 (!mCachedDevice.isConnected() || mCachedDevice.isBusy()) {
|
||||
summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
|
||||
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),
|
||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON,
|
||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY,
|
||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING,
|
||||
R.string.bluetooth_left_name,
|
||||
LEFT_DEVICE_ID);
|
||||
if (disconnected.get()) {
|
||||
summary.setText(summaryText.get());
|
||||
updateDisconnectLayout();
|
||||
return;
|
||||
}
|
||||
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,
|
||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING,
|
||||
R.string.bluetooth_left_name,
|
||||
LEFT_DEVICE_ID);
|
||||
|
||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_ICON,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING,
|
||||
R.string.bluetooth_middle_name,
|
||||
CASE_DEVICE_ID);
|
||||
updateSubLayout(
|
||||
mLayoutPreference.findViewById(R.id.layout_middle),
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_ICON,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING,
|
||||
R.string.bluetooth_middle_name,
|
||||
CASE_DEVICE_ID);
|
||||
|
||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING,
|
||||
R.string.bluetooth_right_name,
|
||||
RIGHT_DEVICE_ID);
|
||||
updateSubLayout(
|
||||
mLayoutPreference.findViewById(R.id.layout_right),
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING,
|
||||
R.string.bluetooth_right_name,
|
||||
RIGHT_DEVICE_ID);
|
||||
|
||||
showBothDevicesBatteryPredictionIfNecessary();
|
||||
} else {
|
||||
mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
|
||||
mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
|
||||
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),
|
||||
BluetoothDevice.METADATA_MAIN_ICON,
|
||||
BluetoothDevice.METADATA_MAIN_BATTERY,
|
||||
BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
|
||||
BluetoothDevice.METADATA_MAIN_CHARGING,
|
||||
/* titleResId */ 0,
|
||||
MAIN_DEVICE_ID);
|
||||
}
|
||||
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,
|
||||
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(
|
||||
|
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user