From 5cb4d251ee67eb232700844573b4a2936815cc08 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 14 Feb 2019 15:56:52 -0800 Subject: [PATCH] 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 --- ...ancedBluetoothDetailsHeaderController.java | 69 +++++++++++++++++-- ...dBluetoothDetailsHeaderControllerTest.java | 28 +++++++- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java index 4b8efd4e371..a09018ea39a 100644 --- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java +++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java @@ -21,6 +21,7 @@ import android.content.Context; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -33,12 +34,16 @@ import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.BatteryMeterView; 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; /** * 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 LayoutPreference mLayoutPreference; @@ -63,6 +68,16 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont refresh(); } + @Override + public void onStart() { + mCachedDevice.registerCallback(this::onDeviceAttributesChanged); + } + + @Override + public void onStop() { + mCachedDevice.unregisterCallback(this::onDeviceAttributesChanged); + } + public void init(CachedBluetoothDevice cachedBluetoothDevice) { mCachedDevice = cachedBluetoothDevice; } @@ -75,25 +90,33 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary); summary.setText(mCachedDevice.getConnectionSummary()); + if (!mCachedDevice.isConnected()) { + updateDisconnectLayout(); + return; + } + updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left), BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON, BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY, + BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING, R.string.bluetooth_left_name); updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle), BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON, BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY, + BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING, R.string.bluetooth_middle_name); updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right), BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY, + BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING, R.string.bluetooth_right_name); } } @VisibleForTesting - Drawable createBtBatteryIcon(Context context, int level) { + Drawable createBtBatteryIcon(Context context, int level, boolean charging) { final BatteryMeterView.BatteryMeterDrawable drawable = new BatteryMeterView.BatteryMeterDrawable(context, context.getColor(R.color.meter_background_color)); @@ -103,12 +126,13 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont com.android.settings.Utils.getColorAttrDefaultColor(context, android.R.attr.colorControlNormal), PorterDuff.Mode.SRC_IN)); + drawable.setCharging(charging); return drawable; } private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey, - int titleResId) { + int chargeMetaKey, int titleResId) { if (linearLayout == null) { return; } @@ -121,14 +145,51 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont } final int batteryLevel = Utils.getIntMetaData(bluetoothDevice, batteryMetaKey); + final boolean charging = Utils.getBooleanMetaData(bluetoothDevice, chargeMetaKey); if (batteryLevel != Utils.META_INT_ERROR) { + linearLayout.setVisibility(View.VISIBLE); 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); 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); 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(); + } } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java index a74610e1a3d..e6462731b98 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java @@ -24,6 +24,7 @@ import android.bluetooth.BluetoothDevice; import android.content.Context; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; +import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; @@ -74,16 +75,18 @@ public class AdvancedBluetoothDetailsHeaderControllerTest{ @Test 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); final BatteryMeterView.BatteryMeterDrawable iconDrawable = (BatteryMeterView.BatteryMeterDrawable) drawable; assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN); + assertThat(iconDrawable.getCharging()).isTrue(); } @Test - public void refresh_updateCorrectInfo() { + public void refresh_connected_updateCorrectInfo() { when(mBluetoothDevice.getMetadata( BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn( String.valueOf(BATTERY_LEVEL_LEFT)); @@ -93,6 +96,7 @@ public class AdvancedBluetoothDetailsHeaderControllerTest{ when(mBluetoothDevice.getMetadata( BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY)).thenReturn( String.valueOf(BATTERY_LEVEL_MAIN)); + when(mCachedDevice.isConnected()).thenReturn(true); mController.refresh(); 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); } + @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 public void getAvailabilityStatus_unthetheredHeadset_returnAvailable() { when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))