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
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 4b8efd4..a09018e 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -21,6 +21,7 @@
 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.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 @@
         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 @@
             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 @@
                 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 @@
         }
 
         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 a74610e..e646273 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.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 @@
 
     @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 @@
         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);
@@ -101,6 +105,26 @@
     }
 
     @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))
                 .thenReturn("true");