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;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import static com.android.settings.bluetooth.Utils.preloadAndRun;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -55,9 +57,13 @@ import com.android.settingslib.utils.StringUtil;
|
|||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -236,63 +242,87 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void refresh() {
|
void refresh() {
|
||||||
if (mLayoutPreference != null && mCachedDevice != null) {
|
if (mLayoutPreference != null && mCachedDevice != null) {
|
||||||
final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
|
Supplier<String> deviceName = Suppliers.memoize(() -> mCachedDevice.getName());
|
||||||
title.setText(mCachedDevice.getName());
|
Supplier<Boolean> disconnected =
|
||||||
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
|
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()) {
|
if (disconnected.get()) {
|
||||||
summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
|
summary.setText(summaryText.get());
|
||||||
updateDisconnectLayout();
|
updateDisconnectLayout();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final BluetoothDevice device = mCachedDevice.getDevice();
|
if (isUntetheredHeadset.get()) {
|
||||||
final String deviceType = BluetoothUtils.getStringMetaData(device,
|
summary.setText(summaryText.get());
|
||||||
BluetoothDevice.METADATA_DEVICE_TYPE);
|
updateSubLayout(
|
||||||
if (TextUtils.equals(deviceType,
|
mLayoutPreference.findViewById(R.id.layout_left),
|
||||||
BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)
|
BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON,
|
||||||
|| BluetoothUtils.getBooleanMetaData(device,
|
BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY,
|
||||||
BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
|
BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
|
||||||
summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
|
BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING,
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left),
|
R.string.bluetooth_left_name,
|
||||||
BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON,
|
LEFT_DEVICE_ID);
|
||||||
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),
|
updateSubLayout(
|
||||||
BluetoothDevice.METADATA_UNTETHERED_CASE_ICON,
|
mLayoutPreference.findViewById(R.id.layout_middle),
|
||||||
BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY,
|
BluetoothDevice.METADATA_UNTETHERED_CASE_ICON,
|
||||||
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
|
BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY,
|
||||||
BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING,
|
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
|
||||||
R.string.bluetooth_middle_name,
|
BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING,
|
||||||
CASE_DEVICE_ID);
|
R.string.bluetooth_middle_name,
|
||||||
|
CASE_DEVICE_ID);
|
||||||
|
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
|
updateSubLayout(
|
||||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON,
|
mLayoutPreference.findViewById(R.id.layout_right),
|
||||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY,
|
BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON,
|
||||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
|
BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY,
|
||||||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING,
|
BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
|
||||||
R.string.bluetooth_right_name,
|
BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING,
|
||||||
RIGHT_DEVICE_ID);
|
R.string.bluetooth_right_name,
|
||||||
|
RIGHT_DEVICE_ID);
|
||||||
|
|
||||||
showBothDevicesBatteryPredictionIfNecessary();
|
showBothDevicesBatteryPredictionIfNecessary();
|
||||||
} else {
|
} else {
|
||||||
mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
|
mLayoutPreference
|
||||||
mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
|
.findViewById(R.id.layout_left)
|
||||||
|
.setVisibility(View.GONE);
|
||||||
|
mLayoutPreference
|
||||||
|
.findViewById(R.id.layout_right)
|
||||||
|
.setVisibility(View.GONE);
|
||||||
|
|
||||||
summary.setText(mCachedDevice.getConnectionSummary(
|
summary.setText(summaryText.get());
|
||||||
BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
|
updateSubLayout(
|
||||||
!= BluetoothUtils.META_INT_ERROR));
|
mLayoutPreference.findViewById(R.id.layout_middle),
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
|
BluetoothDevice.METADATA_MAIN_ICON,
|
||||||
BluetoothDevice.METADATA_MAIN_ICON,
|
BluetoothDevice.METADATA_MAIN_BATTERY,
|
||||||
BluetoothDevice.METADATA_MAIN_BATTERY,
|
BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
|
||||||
BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
|
BluetoothDevice.METADATA_MAIN_CHARGING,
|
||||||
BluetoothDevice.METADATA_MAIN_CHARGING,
|
/* titleResId= */ 0,
|
||||||
/* titleResId */ 0,
|
MAIN_DEVICE_ID);
|
||||||
MAIN_DEVICE_ID);
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,13 +345,87 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey,
|
private void updateSubLayout(
|
||||||
int lowBatteryMetaKey, int chargeMetaKey, int titleResId, int deviceId) {
|
LinearLayout linearLayout,
|
||||||
|
int iconMetaKey,
|
||||||
|
int batteryMetaKey,
|
||||||
|
int lowBatteryMetaKey,
|
||||||
|
int chargeMetaKey,
|
||||||
|
int titleResId,
|
||||||
|
int deviceId) {
|
||||||
if (linearLayout == null) {
|
if (linearLayout == null) {
|
||||||
return;
|
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 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);
|
final ImageView imageView = linearLayout.findViewById(R.id.header_icon);
|
||||||
if (iconUri != null) {
|
if (iconUri != null) {
|
||||||
updateIcon(imageView, iconUri);
|
updateIcon(imageView, iconUri);
|
||||||
@@ -331,17 +435,9 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
imageView.setImageDrawable(pair.first);
|
imageView.setImageDrawable(pair.first);
|
||||||
imageView.setContentDescription(pair.second);
|
imageView.setContentDescription(pair.second);
|
||||||
}
|
}
|
||||||
final int batteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice, batteryMetaKey);
|
final int batteryLevel = preloadedBatteryLevel.get();
|
||||||
final boolean charging = BluetoothUtils.getBooleanMetaData(bluetoothDevice, chargeMetaKey);
|
final boolean charging = preloadedCharging.get();
|
||||||
int lowBatteryLevel = BluetoothUtils.getIntMetaData(bluetoothDevice,
|
int lowBatteryLevel = preloadedLowBatteryLevel.get();
|
||||||
lowBatteryMetaKey);
|
|
||||||
if (lowBatteryLevel == BluetoothUtils.META_INT_ERROR) {
|
|
||||||
if (batteryMetaKey == BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY) {
|
|
||||||
lowBatteryLevel = CASE_LOW_BATTERY_LEVEL;
|
|
||||||
} else {
|
|
||||||
lowBatteryLevel = LOW_BATTERY_LEVEL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG, "buletoothDevice: " + bluetoothDevice.getAnonymizedAddress()
|
Log.d(TAG, "buletoothDevice: " + bluetoothDevice.getAnonymizedAddress()
|
||||||
+ ", updateSubLayout() icon : " + iconMetaKey + ", battery : " + batteryMetaKey
|
+ ", updateSubLayout() icon : " + iconMetaKey + ", battery : " + batteryMetaKey
|
||||||
@@ -353,7 +449,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
showBatteryPredictionIfNecessary(linearLayout, deviceId, batteryLevel);
|
showBatteryPredictionIfNecessary(linearLayout, deviceId, batteryLevel);
|
||||||
}
|
}
|
||||||
final TextView batterySummaryView = linearLayout.findViewById(R.id.bt_battery_summary);
|
final TextView batterySummaryView = linearLayout.findViewById(R.id.bt_battery_summary);
|
||||||
if (isUntetheredHeadset(bluetoothDevice)) {
|
if (preloadedIsUntethered.get()) {
|
||||||
if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
|
if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
|
||||||
linearLayout.setVisibility(View.VISIBLE);
|
linearLayout.setVisibility(View.VISIBLE);
|
||||||
batterySummaryView.setText(
|
batterySummaryView.setText(
|
||||||
@@ -364,7 +460,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
if (deviceId == MAIN_DEVICE_ID) {
|
if (deviceId == MAIN_DEVICE_ID) {
|
||||||
linearLayout.setVisibility(View.VISIBLE);
|
linearLayout.setVisibility(View.VISIBLE);
|
||||||
linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE);
|
linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE);
|
||||||
int level = bluetoothDevice.getBatteryLevel();
|
int level = preloadedNativeBatteryLevel.get();
|
||||||
if (level != BluetoothDevice.BATTERY_LEVEL_UNKNOWN
|
if (level != BluetoothDevice.BATTERY_LEVEL_UNKNOWN
|
||||||
&& level != BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF) {
|
&& level != BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF) {
|
||||||
batterySummaryView.setText(
|
batterySummaryView.setText(
|
||||||
|
@@ -37,12 +37,16 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.flags.Flags;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -272,4 +276,22 @@ public final class Utils {
|
|||||||
+ " , deviceList = " + cachedBluetoothDevices);
|
+ " , deviceList = " + cachedBluetoothDevices);
|
||||||
return 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