Update advanced bt header
1. Add callback to listen to device update 2. Add charging support for bt battery icon 3. When disconnected, only show main icon Follow CL will update battery icon to show exclamation when it is low. Bug: 124455912 Test: RunSettingsRoboTests Change-Id: I03fb3bf4c4b77711e14b1f2f53733771b525fe4b
This commit is contained in:
@@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
import android.graphics.PorterDuffColorFilter;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -33,12 +34,16 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.fuelgauge.BatteryMeterView;
|
import com.android.settings.fuelgauge.BatteryMeterView;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class adds a header with device name and status (connected/disconnected, etc.).
|
* This class adds a header with device name and status (connected/disconnected, etc.).
|
||||||
*/
|
*/
|
||||||
public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController {
|
public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController implements
|
||||||
|
LifecycleObserver, OnStart, OnStop, CachedBluetoothDevice.Callback {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
LayoutPreference mLayoutPreference;
|
LayoutPreference mLayoutPreference;
|
||||||
@@ -63,6 +68,16 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
mCachedDevice.registerCallback(this::onDeviceAttributesChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
mCachedDevice.unregisterCallback(this::onDeviceAttributesChanged);
|
||||||
|
}
|
||||||
|
|
||||||
public void init(CachedBluetoothDevice cachedBluetoothDevice) {
|
public void init(CachedBluetoothDevice cachedBluetoothDevice) {
|
||||||
mCachedDevice = cachedBluetoothDevice;
|
mCachedDevice = cachedBluetoothDevice;
|
||||||
}
|
}
|
||||||
@@ -75,25 +90,33 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
|
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
|
||||||
summary.setText(mCachedDevice.getConnectionSummary());
|
summary.setText(mCachedDevice.getConnectionSummary());
|
||||||
|
|
||||||
|
if (!mCachedDevice.isConnected()) {
|
||||||
|
updateDisconnectLayout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left),
|
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left),
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
|
BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
|
BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
|
||||||
|
BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING,
|
||||||
R.string.bluetooth_left_name);
|
R.string.bluetooth_left_name);
|
||||||
|
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
|
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
|
BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
|
BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
|
||||||
|
BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING,
|
||||||
R.string.bluetooth_middle_name);
|
R.string.bluetooth_middle_name);
|
||||||
|
|
||||||
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
|
updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
|
BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
|
BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
|
||||||
|
BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING,
|
||||||
R.string.bluetooth_right_name);
|
R.string.bluetooth_right_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Drawable createBtBatteryIcon(Context context, int level) {
|
Drawable createBtBatteryIcon(Context context, int level, boolean charging) {
|
||||||
final BatteryMeterView.BatteryMeterDrawable drawable =
|
final BatteryMeterView.BatteryMeterDrawable drawable =
|
||||||
new BatteryMeterView.BatteryMeterDrawable(context,
|
new BatteryMeterView.BatteryMeterDrawable(context,
|
||||||
context.getColor(R.color.meter_background_color));
|
context.getColor(R.color.meter_background_color));
|
||||||
@@ -103,12 +126,13 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
||||||
android.R.attr.colorControlNormal),
|
android.R.attr.colorControlNormal),
|
||||||
PorterDuff.Mode.SRC_IN));
|
PorterDuff.Mode.SRC_IN));
|
||||||
|
drawable.setCharging(charging);
|
||||||
|
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey,
|
private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey,
|
||||||
int titleResId) {
|
int chargeMetaKey, int titleResId) {
|
||||||
if (linearLayout == null) {
|
if (linearLayout == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,14 +145,51 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int batteryLevel = Utils.getIntMetaData(bluetoothDevice, batteryMetaKey);
|
final int batteryLevel = Utils.getIntMetaData(bluetoothDevice, batteryMetaKey);
|
||||||
|
final boolean charging = Utils.getBooleanMetaData(bluetoothDevice, chargeMetaKey);
|
||||||
if (batteryLevel != Utils.META_INT_ERROR) {
|
if (batteryLevel != Utils.META_INT_ERROR) {
|
||||||
|
linearLayout.setVisibility(View.VISIBLE);
|
||||||
final ImageView imageView = linearLayout.findViewById(R.id.bt_battery_icon);
|
final ImageView imageView = linearLayout.findViewById(R.id.bt_battery_icon);
|
||||||
imageView.setImageDrawable(createBtBatteryIcon(mContext, batteryLevel));
|
imageView.setImageDrawable(createBtBatteryIcon(mContext, batteryLevel, charging));
|
||||||
|
imageView.setVisibility(View.VISIBLE);
|
||||||
final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary);
|
final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary);
|
||||||
textView.setText(com.android.settings.Utils.formatPercentage(batteryLevel));
|
textView.setText(com.android.settings.Utils.formatPercentage(batteryLevel));
|
||||||
|
textView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
// Hide it if it doesn't have battery information
|
||||||
|
linearLayout.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
final TextView textView = linearLayout.findViewById(R.id.header_title);
|
final TextView textView = linearLayout.findViewById(R.id.header_title);
|
||||||
textView.setText(titleResId);
|
textView.setText(titleResId);
|
||||||
|
textView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisconnectLayout() {
|
||||||
|
mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
|
||||||
|
mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// Hide title, battery icon and battery summary
|
||||||
|
final LinearLayout linearLayout = mLayoutPreference.findViewById(R.id.layout_middle);
|
||||||
|
linearLayout.setVisibility(View.VISIBLE);
|
||||||
|
linearLayout.findViewById(R.id.header_title).setVisibility(View.GONE);
|
||||||
|
linearLayout.findViewById(R.id.bt_battery_summary).setVisibility(View.GONE);
|
||||||
|
linearLayout.findViewById(R.id.bt_battery_icon).setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// Only show bluetooth icon
|
||||||
|
final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
|
||||||
|
final String iconUri = Utils.getStringMetaData(bluetoothDevice,
|
||||||
|
BluetoothDevice.METADATA_MAIN_ICON);
|
||||||
|
if (iconUri != null) {
|
||||||
|
final ImageView imageView = linearLayout.findViewById(R.id.header_icon);
|
||||||
|
final IconCompat iconCompat = IconCompat.createWithContentUri(iconUri);
|
||||||
|
imageView.setImageBitmap(iconCompat.getBitmap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeviceAttributesChanged() {
|
||||||
|
if (mCachedDevice != null) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -74,16 +75,18 @@ public class AdvancedBluetoothDetailsHeaderControllerTest{
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createBatteryIcon_hasCorrectInfo() {
|
public void createBatteryIcon_hasCorrectInfo() {
|
||||||
final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL_MAIN);
|
final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL_MAIN,
|
||||||
|
true /* charging */);
|
||||||
assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class);
|
assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class);
|
||||||
|
|
||||||
final BatteryMeterView.BatteryMeterDrawable iconDrawable =
|
final BatteryMeterView.BatteryMeterDrawable iconDrawable =
|
||||||
(BatteryMeterView.BatteryMeterDrawable) drawable;
|
(BatteryMeterView.BatteryMeterDrawable) drawable;
|
||||||
assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN);
|
assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN);
|
||||||
|
assertThat(iconDrawable.getCharging()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void refresh_updateCorrectInfo() {
|
public void refresh_connected_updateCorrectInfo() {
|
||||||
when(mBluetoothDevice.getMetadata(
|
when(mBluetoothDevice.getMetadata(
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
|
BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
|
||||||
String.valueOf(BATTERY_LEVEL_LEFT));
|
String.valueOf(BATTERY_LEVEL_LEFT));
|
||||||
@@ -93,6 +96,7 @@ public class AdvancedBluetoothDetailsHeaderControllerTest{
|
|||||||
when(mBluetoothDevice.getMetadata(
|
when(mBluetoothDevice.getMetadata(
|
||||||
BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY)).thenReturn(
|
BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY)).thenReturn(
|
||||||
String.valueOf(BATTERY_LEVEL_MAIN));
|
String.valueOf(BATTERY_LEVEL_MAIN));
|
||||||
|
when(mCachedDevice.isConnected()).thenReturn(true);
|
||||||
mController.refresh();
|
mController.refresh();
|
||||||
|
|
||||||
assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT);
|
assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT);
|
||||||
@@ -100,6 +104,26 @@ public class AdvancedBluetoothDetailsHeaderControllerTest{
|
|||||||
assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN);
|
assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void refresh_disconnected_updateCorrectInfo() {
|
||||||
|
when(mCachedDevice.isConnected()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.refresh();
|
||||||
|
|
||||||
|
final LinearLayout layout = mLayoutPreference.findViewById(R.id.layout_middle);
|
||||||
|
|
||||||
|
assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo(
|
||||||
|
View.GONE);
|
||||||
|
assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo(
|
||||||
|
View.GONE);
|
||||||
|
assertThat(layout.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(layout.findViewById(R.id.header_title).getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(layout.findViewById(R.id.bt_battery_summary).getVisibility()).isEqualTo(
|
||||||
|
View.GONE);
|
||||||
|
assertThat(layout.findViewById(R.id.bt_battery_icon).getVisibility()).isEqualTo(View.GONE);
|
||||||
|
assertThat(layout.findViewById(R.id.header_icon).getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_unthetheredHeadset_returnAvailable() {
|
public void getAvailabilityStatus_unthetheredHeadset_returnAvailable() {
|
||||||
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
|
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
|
||||||
|
Reference in New Issue
Block a user