Add the battery information into device details header

Add the new LE audio header
Add the battery information
Update the condition for non-LE audio header

Bug: 218626547
Test: build pass and manualy test
Change-Id: Ib9f4c388c369dc374c43dd399111e02b5555159b
diff --git a/res/layout/le_audio_bt_entity_header.xml b/res/layout/le_audio_bt_entity_header.xml
new file mode 100644
index 0000000..6e2a1e8
--- /dev/null
+++ b/res/layout/le_audio_bt_entity_header.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/entity_header"
+    style="@style/EntityHeader"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_centerHorizontal="true"
+    android:gravity="center_horizontal"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/entity_header_title"
+        style="@style/TextAppearance.EntityHeaderTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:singleLine="false"
+        android:ellipsize="marquee"
+        android:textDirection="locale"/>
+
+    <TextView
+        android:id="@+id/entity_header_summary"
+        style="@style/TextAppearance.EntityHeaderSummary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="4dp"
+        android:singleLine="false"
+        android:ellipsize="marquee"
+        android:textDirection="locale"/>
+
+    <ImageView
+        android:id="@+id/entity_header_icon"
+        android:layout_width="72dp"
+        android:layout_height="72dp"
+        android:layout_marginTop="24dp"
+        android:scaleType="fitCenter"
+        android:antialias="true"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/le_bluetooth_battery_start_margin"
+            android:orientation="vertical">
+            <TextView
+                android:id="@+id/bt_battery_case_title"
+                style="@style/TextAppearance.EntityHeaderTitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:gravity="start|center_vertical"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                android:text="@string/bluetooth_middle_name"
+                android:textSize="@dimen/advanced_bluetooth_header_title_text_size"
+                android:visibility="gone"/>
+            <TextView
+                android:id="@+id/bt_battery_left_title"
+                style="@style/TextAppearance.EntityHeaderTitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:gravity="start|center_vertical"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                android:text="@string/bluetooth_left_name"
+                android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
+            <TextView
+                android:id="@+id/bt_battery_right_title"
+                style="@style/TextAppearance.EntityHeaderTitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:gravity="start|center_vertical"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                android:text="@string/bluetooth_right_name"
+                android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/le_bluetooth_summary_start_margin"
+            android:orientation="vertical">
+            <TextView
+                android:id="@+id/bt_battery_case_summary"
+                style="@style/TextAppearance.EntityHeaderSummary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:padding="@dimen/le_bluetooth_summary_padding"
+                android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"
+                android:visibility="gone"/>
+            <TextView
+                android:id="@+id/bt_battery_left_summary"
+                style="@style/TextAppearance.EntityHeaderSummary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:padding="@dimen/le_bluetooth_summary_padding"
+                android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
+            <TextView
+                android:id="@+id/bt_battery_right_summary"
+                style="@style/TextAppearance.EntityHeaderSummary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
+                android:padding="@dimen/le_bluetooth_summary_padding"
+                android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c44a1cb..8a59da2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -399,6 +399,13 @@
     <dimen name="advanced_bluetooth_battery_height">27.5dp</dimen>
     <dimen name="advanced_bluetooth_battery_right_margin">-4dp</dimen>
 
+    <!-- Header layout of LE audio bluetooth device at bluretooth device detalis -->
+    <dimen name="le_bluetooth_battery_top_margin">5dp</dimen>
+    <dimen name="le_bluetooth_battery_start_margin">10dp</dimen>
+    <dimen name="le_bluetooth_summary_drawable_padding">6dp</dimen>
+    <dimen name="le_bluetooth_summary_start_margin">20dp</dimen>
+    <dimen name="le_bluetooth_summary_padding">1.5dp</dimen>
+
     <!-- Developer option bluetooth settings dialog -->
     <dimen name="developer_option_dialog_margin_start">8dp</dimen>
     <dimen name="developer_option_dialog_margin_top">8dp</dimen>
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index b21d5c9..7ad1930 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -34,6 +34,14 @@
         settings:searchable="false"
         settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/>
 
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="le_audio_bluetooth_device_header"
+        android:layout="@layout/le_audio_bt_entity_header"
+        android:selectable="false"
+        settings:allowDividerBelow="true"
+        settings:searchable="false"
+        settings:controller="com.android.settings.bluetooth.LeAudioBluetoothDetailsHeaderController"/>
+
     <com.android.settingslib.widget.ActionButtonsPreference
         android:key="action_buttons"
         settings:allowDividerBelow="true"/>
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index 9f5e78e..9c7aa58 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
@@ -53,7 +54,10 @@
 
     @Override
     public boolean isAvailable() {
-        return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice());
+        boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
+                .stream()
+                .anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
+        return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && !hasLeAudio;
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 6532482..6d443ee 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -117,6 +117,7 @@
             return;
         }
         use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
+        use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
 
         final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
                 context).getBluetoothFeatureProvider(context);
diff --git a/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java
new file mode 100644
index 0000000..06cee85
--- /dev/null
+++ b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.fuelgauge.BatteryMeterView;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.widget.LayoutPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class adds a header with device name and status (connected/disconnected, etc.).
+ */
+public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceController implements
+        LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
+    private static final String TAG = "LeAudioBtHeaderCtrl";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    @VisibleForTesting
+    static final int LEFT_DEVICE_ID =
+            BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
+                    | BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE
+                    | BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND;
+
+    @VisibleForTesting
+    static final int RIGHT_DEVICE_ID =
+            BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
+                    | BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE
+                    | BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND;
+
+    @VisibleForTesting
+    static final int INVALID_RESOURCE_ID = -1;
+
+    @VisibleForTesting
+    LayoutPreference mLayoutPreference;
+    private CachedBluetoothDevice mCachedDevice;
+    @VisibleForTesting
+    Handler mHandler = new Handler(Looper.getMainLooper());
+    @VisibleForTesting
+    boolean mIsRegisterCallback = false;
+
+    private LocalBluetoothProfileManager mProfileManager;
+
+    public LeAudioBluetoothDetailsHeaderController(Context context, String prefKey) {
+        super(context, prefKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mCachedDevice == null || mProfileManager == null) {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
+        boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
+                .stream()
+                .anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
+
+        return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && hasLeAudio
+                ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mLayoutPreference = screen.findPreference(getPreferenceKey());
+        mLayoutPreference.setVisible(isAvailable());
+    }
+
+    @Override
+    public void onStart() {
+        if (!isAvailable()) {
+            return;
+        }
+        mIsRegisterCallback = true;
+        mCachedDevice.registerCallback(this);
+        refresh();
+    }
+
+    @Override
+    public void onStop() {
+        if (!mIsRegisterCallback) {
+            return;
+        }
+        mCachedDevice.unregisterCallback(this);
+        mIsRegisterCallback = false;
+    }
+
+    @Override
+    public void onDestroy() {
+    }
+
+    public void init(CachedBluetoothDevice cachedBluetoothDevice,
+            LocalBluetoothManager bluetoothManager) {
+        mCachedDevice = cachedBluetoothDevice;
+        mProfileManager = bluetoothManager.getProfileManager();
+    }
+
+    @VisibleForTesting
+    void refresh() {
+        if (mLayoutPreference == null || mCachedDevice == null) {
+            return;
+        }
+        final ImageView imageView = mLayoutPreference.findViewById(R.id.entity_header_icon);
+        if (imageView != null) {
+            final Pair<Drawable, String> pair =
+                    BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
+            imageView.setImageDrawable(pair.first);
+            imageView.setContentDescription(pair.second);
+        }
+
+        final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
+        if (title != null) {
+            title.setText(mCachedDevice.getName());
+        }
+        final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
+        if (summary != null) {
+            summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
+        }
+
+        if (!mCachedDevice.isConnected() || mCachedDevice.isBusy()) {
+            hideAllOfBatteryLayouts();
+            return;
+        }
+
+        updateBatteryLayout();
+    }
+
+    @VisibleForTesting
+    Drawable createBtBatteryIcon(Context context, int level) {
+        final BatteryMeterView.BatteryMeterDrawable drawable =
+                new BatteryMeterView.BatteryMeterDrawable(context,
+                        context.getColor(R.color.meter_background_color),
+                        context.getResources().getDimensionPixelSize(
+                                R.dimen.advanced_bluetooth_battery_meter_width),
+                        context.getResources().getDimensionPixelSize(
+                                R.dimen.advanced_bluetooth_battery_meter_height));
+        drawable.setBatteryLevel(level);
+        drawable.setColorFilter(new PorterDuffColorFilter(
+                com.android.settings.Utils.getColorAttrDefaultColor(context,
+                        android.R.attr.colorControlNormal),
+                PorterDuff.Mode.SRC));
+        return drawable;
+    }
+
+    private int getBatteryTitleResource(int deviceId) {
+        if (deviceId == LEFT_DEVICE_ID) {
+            return R.id.bt_battery_left_title;
+        }
+        if (deviceId == RIGHT_DEVICE_ID) {
+            return R.id.bt_battery_right_title;
+        }
+        Log.d(TAG, "No resource id. The deviceId is " + deviceId);
+        return INVALID_RESOURCE_ID;
+    }
+
+    private int getBatterySummaryResource(int deviceId) {
+        if (deviceId == LEFT_DEVICE_ID) {
+            return R.id.bt_battery_left_summary;
+        }
+        if (deviceId == RIGHT_DEVICE_ID) {
+            return R.id.bt_battery_right_summary;
+        }
+        Log.d(TAG, "No resource id. The deviceId is " + deviceId);
+        return INVALID_RESOURCE_ID;
+    }
+
+    private void hideAllOfBatteryLayouts() {
+        // hide the case
+        updateBatteryLayout(R.id.bt_battery_case_title, R.id.bt_battery_case_summary,
+                BluetoothUtils.META_INT_ERROR);
+        // hide the left
+        updateBatteryLayout(R.id.bt_battery_left_title, R.id.bt_battery_left_summary,
+                BluetoothUtils.META_INT_ERROR);
+        // hide the right
+        updateBatteryLayout(R.id.bt_battery_right_title, R.id.bt_battery_right_summary,
+                BluetoothUtils.META_INT_ERROR);
+    }
+
+    private List<CachedBluetoothDevice> getAllOfLeAudioDevices() {
+        if (mCachedDevice == null) {
+            return null;
+        }
+        List<CachedBluetoothDevice> leAudioDevices = new ArrayList<>();
+        leAudioDevices.add(mCachedDevice);
+        if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+            for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) {
+                leAudioDevices.add(member);
+            }
+        }
+        return leAudioDevices;
+    }
+
+    private void updateBatteryLayout() {
+        // Init the battery layouts.
+        hideAllOfBatteryLayouts();
+        final List<CachedBluetoothDevice> leAudioDevices = getAllOfLeAudioDevices();
+        LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
+        if (leAudioDevices == null || leAudioDevices.isEmpty()) {
+            Log.e(TAG, "There is no LeAudioProfile.");
+            return;
+        }
+
+        if (!leAudioProfile.isEnabled(mCachedDevice.getDevice())) {
+            Log.d(TAG, "Show the legacy battery style if the LeAudio is not enabled.");
+            final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
+            if (summary != null) {
+                summary.setText(mCachedDevice.getConnectionSummary());
+            }
+            return;
+        }
+
+        for (CachedBluetoothDevice cachedDevice : leAudioDevices) {
+            int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
+            Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress()
+                    + ", deviceId:" + deviceId);
+
+            if (deviceId == BluetoothLeAudio.AUDIO_LOCATION_INVALID) {
+                Log.d(TAG, "The device does not support the AUDIO_LOCATION.");
+                return;
+            }
+            boolean isLeft = (deviceId & LEFT_DEVICE_ID) != 0;
+            boolean isRight = (deviceId & LEFT_DEVICE_ID) != 0;
+            boolean isLeftRight = isLeft && isRight;
+            // The LE device updates the BatteryLayout
+            if (isLeftRight) {
+                Log.d(TAG, "The device id is left+right. Do nothing.");
+            } else if (isLeft) {
+                updateBatteryLayout(getBatteryTitleResource(LEFT_DEVICE_ID),
+                        getBatterySummaryResource(LEFT_DEVICE_ID), cachedDevice.getBatteryLevel());
+            } else if (isRight) {
+                updateBatteryLayout(getBatteryTitleResource(RIGHT_DEVICE_ID),
+                        getBatterySummaryResource(RIGHT_DEVICE_ID), cachedDevice.getBatteryLevel());
+            } else {
+                Log.d(TAG, "The device id is other Audio Location. Do nothing.");
+            }
+        }
+    }
+
+    private void updateBatteryLayout(int titleResId, int summaryResId, int batteryLevel) {
+        final TextView batteryTitleView = mLayoutPreference.findViewById(titleResId);
+        final TextView batterySummaryView = mLayoutPreference.findViewById(summaryResId);
+        if (batteryTitleView == null || batterySummaryView == null) {
+            Log.e(TAG, "updateBatteryLayout: No TextView");
+            return;
+        }
+        if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
+            batteryTitleView.setVisibility(View.VISIBLE);
+            batterySummaryView.setVisibility(View.VISIBLE);
+            batterySummaryView.setText(
+                    com.android.settings.Utils.formatPercentage(batteryLevel));
+            batterySummaryView.setCompoundDrawablesRelativeWithIntrinsicBounds(
+                    createBtBatteryIcon(mContext, batteryLevel), /* top */ null,
+                    /* end */ null, /* bottom */ null);
+        } else {
+            Log.d(TAG, "updateBatteryLayout: Hide it if it doesn't have battery information.");
+            batteryTitleView.setVisibility(View.GONE);
+            batterySummaryView.setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public void onDeviceAttributesChanged() {
+        if (mCachedDevice != null) {
+            refresh();
+        }
+    }
+}