Move rename button next to the device name

BUG: 343317785
Test: atest GeneralBluetoothDetailsHeaderControllerTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: I87f030ca48d3edac13759fe51499b7e400dbb795
diff --git a/res/layout/advanced_bt_entity_header.xml b/res/layout/advanced_bt_entity_header.xml
index 833f6bd..37ae843 100644
--- a/res/layout/advanced_bt_entity_header.xml
+++ b/res/layout/advanced_bt_entity_header.xml
@@ -17,6 +17,7 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/entity_header"
     style="@style/EntityHeader"
     android:layout_width="match_parent"
@@ -25,15 +26,41 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/entity_header_title"
-        style="@style/TextAppearance.EntityHeaderTitle"
-        android:layout_width="wrap_content"
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        android:gravity="center"
-        android:ellipsize="marquee"
-        android:textDirection="locale"/>
+        android:gravity="center">
+
+        <TextView
+            android:id="@+id/entity_header_title"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:ellipsize="marquee"
+            android:textDirection="locale"
+            android:layout_marginStart="48dp"
+            android:layout_marginEnd="48dp"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constrainedWidth="true" />
+        <ImageButton
+            android:id="@+id/rename_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minWidth="@dimen/min_tap_target_size"
+            android:minHeight="@dimen/min_tap_target_size"
+            android:background="@android:color/transparent"
+            android:src="@drawable/ic_mode_edit"
+            android:contentDescription="@string/bluetooth_rename_button"
+            android:tint="@color/settingslib_materialColorOnSurface"
+            app:layout_constraintStart_toEndOf="@+id/entity_header_title"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:visibility="gone" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
     <TextView
         android:id="@+id/entity_header_summary"
diff --git a/res/layout/general_bt_entity_header.xml b/res/layout/general_bt_entity_header.xml
new file mode 100644
index 0000000..ec15b12
--- /dev/null
+++ b/res/layout/general_bt_entity_header.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2024 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"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    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">
+
+    <ImageView
+        android:id="@+id/bt_header_icon"
+        android:importantForAccessibility="no"
+        style="@style/SettingsLibEntityHeaderIcon"/>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="8dp"
+        android:gravity="center">
+        <TextView
+            android:id="@+id/bt_header_device_name"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:gravity="center"
+            android:ellipsize="marquee"
+            android:textDirection="locale"
+            android:layout_marginStart="48dp"
+            android:layout_marginEnd="48dp"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constrainedWidth="true" />
+        <ImageButton
+            android:id="@+id/rename_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minWidth="@dimen/min_tap_target_size"
+            android:minHeight="@dimen/min_tap_target_size"
+            android:background="@android:color/transparent"
+            android:src="@drawable/ic_mode_edit"
+            android:contentDescription="@string/bluetooth_rename_button"
+            android:tint="@color/settingslib_materialColorOnSurface"
+            app:layout_constraintStart_toEndOf="@+id/bt_header_device_name"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <TextView
+        android:id="@+id/bt_header_connection_summary"
+        style="@style/TextAppearance.EntityHeaderSummary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="2dp"
+        android:singleLine="false"
+        android:textAlignment="center"/>
+</LinearLayout>
diff --git a/res/layout/le_audio_bt_entity_header.xml b/res/layout/le_audio_bt_entity_header.xml
index 460ae69..81911e9 100644
--- a/res/layout/le_audio_bt_entity_header.xml
+++ b/res/layout/le_audio_bt_entity_header.xml
@@ -17,6 +17,7 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/entity_header"
     style="@style/EntityHeader"
     android:layout_width="match_parent"
@@ -27,15 +28,42 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/entity_header_title"
-        style="@style/TextAppearance.EntityHeaderTitle"
-        android:layout_width="wrap_content"
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        android:gravity="center"
-        android:ellipsize="marquee"
-        android:textDirection="locale"/>
+        android:gravity="center">
+        <TextView
+            android:id="@+id/entity_header_title"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:gravity="center"
+            android:ellipsize="marquee"
+            android:textDirection="locale"
+            android:layout_marginStart="48dp"
+            android:layout_marginEnd="48dp"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constrainedWidth="true" />
+        <ImageButton
+            android:id="@+id/rename_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minWidth="@dimen/min_tap_target_size"
+            android:minHeight="@dimen/min_tap_target_size"
+            android:background="@android:color/transparent"
+            android:src="@drawable/ic_mode_edit"
+            android:contentDescription="@string/bluetooth_rename_button"
+            android:tint="@color/settingslib_materialColorOnSurface"
+            app:layout_constraintStart_toEndOf="@+id/entity_header_title"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            android:visibility="gone" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
     <TextView
         android:id="@+id/entity_header_summary"
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 91f73a7..f2e9e73 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -27,6 +27,13 @@
         settings:searchable="false"/>
 
     <com.android.settingslib.widget.LayoutPreference
+        android:key="general_bluetooth_device_header"
+        android:layout="@layout/general_bt_entity_header"
+        android:selectable="false"
+        settings:allowDividerBelow="true"
+        settings:searchable="false"/>
+
+    <com.android.settingslib.widget.LayoutPreference
         android:key="advanced_bluetooth_device_header"
         android:layout="@layout/advanced_bt_entity_header"
         android:selectable="false"
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 11ecf8b..02b8813 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -37,12 +37,14 @@
 import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
@@ -97,6 +99,7 @@
     private static final int MAIN_DEVICE_ID = 4;
     private static final float HALF_ALPHA = 0.5f;
 
+    PreferenceFragmentCompat mFragment;
     @VisibleForTesting
     LayoutPreference mLayoutPreference;
     @VisibleForTesting
@@ -170,8 +173,11 @@
         mIconCache.clear();
     }
 
-    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+    /** Initializes the controller. */
+    public void init(
+            CachedBluetoothDevice cachedBluetoothDevice, PreferenceFragmentCompat fragment) {
         mCachedDevice = cachedBluetoothDevice;
+        mFragment = fragment;
     }
 
     private void registerBluetoothDevice() {
@@ -325,6 +331,14 @@
                                     MAIN_DEVICE_ID);
                         }
                     });
+            if (Flags.enableBluetoothDeviceDetailsPolish()) {
+                ImageButton renameButton = mLayoutPreference.findViewById(R.id.rename_button);
+                renameButton.setVisibility(View.VISIBLE);
+                renameButton.setOnClickListener(view -> {
+                    RemoteDeviceNameDialogFragment.newInstance(mCachedDevice).show(
+                            mFragment.getFragmentManager(), RemoteDeviceNameDialogFragment.TAG);
+                });
+            }
         }
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index 462f422..3fbd445 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -26,6 +26,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
+import com.android.settings.flags.Flags;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -47,6 +48,9 @@
 
     @Override
     public boolean isAvailable() {
+        if (Flags.enableBluetoothDeviceDetailsPolish()) {
+            return false;
+        }
         boolean hasLeAudio = mCachedDevice.getUiAccessibleProfiles()
                 .stream()
                 .anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 5f9957b..ccf38ed 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -50,6 +50,7 @@
 import com.android.settings.connecteddevice.stylus.StylusDevicesController;
 import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.flags.Flags;
 import com.android.settings.inputmethod.KeyboardSettingsPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.slices.SlicePreferenceController;
@@ -213,8 +214,8 @@
             finish();
             return;
         }
-        use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
-        use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
+        use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice, this);
+        use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager, this);
         use(KeyboardSettingsPreferenceController.class).init(mCachedDevice);
 
         final BluetoothFeatureProvider featureProvider =
@@ -338,7 +339,7 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (!mUserManager.isGuestUser()) {
+        if (!Flags.enableBluetoothDeviceDetailsPolish() && !mUserManager.isGuestUser()) {
             MenuItem item = menu.add(0, EDIT_DEVICE_NAME_ITEM_ID, 0,
                     R.string.bluetooth_rename_button);
             item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
@@ -365,6 +366,9 @@
             Lifecycle lifecycle = getSettingsLifecycle();
             controllers.add(new BluetoothDetailsHeaderController(context, this, mCachedDevice,
                     lifecycle));
+            controllers.add(
+                    new GeneralBluetoothDetailsHeaderController(
+                            context, this, mCachedDevice, lifecycle));
             controllers.add(new BluetoothDetailsButtonsController(context, this, mCachedDevice,
                     lifecycle));
             controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
diff --git a/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderController.java
new file mode 100644
index 0000000..57a1027
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderController.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 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.BluetoothProfile;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.Pair;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.LayoutPreference;
+
+/** This class adds a header with device name and status (connected/disconnected, etc.). */
+public class GeneralBluetoothDetailsHeaderController extends BluetoothDetailsController {
+    private static final String KEY_GENERAL_DEVICE_HEADER = "general_bluetooth_device_header";
+
+    @Nullable
+    private LayoutPreference mLayoutPreference;
+
+    public GeneralBluetoothDetailsHeaderController(
+            Context context,
+            PreferenceFragmentCompat fragment,
+            CachedBluetoothDevice device,
+            Lifecycle lifecycle) {
+        super(context, fragment, device, lifecycle);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!Flags.enableBluetoothDeviceDetailsPolish()) {
+            return false;
+        }
+        boolean hasLeAudio =
+                mCachedDevice.getUiAccessibleProfiles().stream()
+                        .anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
+        return !BluetoothUtils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && !hasLeAudio;
+    }
+
+    @Override
+    protected void init(PreferenceScreen screen) {
+        mLayoutPreference = screen.findPreference(KEY_GENERAL_DEVICE_HEADER);
+    }
+
+    @Override
+    protected void refresh() {
+        if (!isAvailable() || mLayoutPreference == null) {
+            return;
+        }
+        ImageView imageView = mLayoutPreference.findViewById(R.id.bt_header_icon);
+        if (imageView != null) {
+            final Pair<Drawable, String> pair =
+                    BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
+            imageView.setImageDrawable(pair.first);
+            imageView.setContentDescription(pair.second);
+        }
+
+        TextView title = mLayoutPreference.findViewById(R.id.bt_header_device_name);
+        if (title != null) {
+            title.setText(mCachedDevice.getName());
+        }
+        TextView summary = mLayoutPreference.findViewById(R.id.bt_header_connection_summary);
+        if (summary != null) {
+            summary.setText(mCachedDevice.getConnectionSummary());
+        }
+        ImageButton renameButton = mLayoutPreference.findViewById(R.id.rename_button);
+        renameButton.setVisibility(View.VISIBLE);
+        renameButton.setOnClickListener(
+                view -> {
+                    RemoteDeviceNameDialogFragment.newInstance(mCachedDevice)
+                            .show(
+                                    mFragment.getFragmentManager(),
+                                    RemoteDeviceNameDialogFragment.TAG);
+                });
+    }
+
+    @Override
+    @NonNull
+    public String getPreferenceKey() {
+        return KEY_GENERAL_DEVICE_HEADER;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java
index a5e9cde..2524894 100644
--- a/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/LeAudioBluetoothDetailsHeaderController.java
@@ -27,14 +27,17 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.flags.Flags;
 import com.android.settings.fuelgauge.BatteryMeterView;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -86,6 +89,7 @@
     @VisibleForTesting
     static final int INVALID_RESOURCE_ID = -1;
 
+    PreferenceFragmentCompat mFragment;
     @VisibleForTesting
     LayoutPreference mLayoutPreference;
     LocalBluetoothManager mManager;
@@ -151,11 +155,12 @@
     }
 
     public void init(CachedBluetoothDevice cachedBluetoothDevice,
-            LocalBluetoothManager bluetoothManager) {
+            LocalBluetoothManager bluetoothManager, PreferenceFragmentCompat fragment) {
         mCachedDevice = cachedBluetoothDevice;
         mManager = bluetoothManager;
         mProfileManager = bluetoothManager.getProfileManager();
         mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
+        mFragment = fragment;
     }
 
     @VisibleForTesting
@@ -163,6 +168,14 @@
         if (mLayoutPreference == null || mCachedDevice == null) {
             return;
         }
+        if (Flags.enableBluetoothDeviceDetailsPolish()) {
+            ImageButton renameButton = mLayoutPreference.findViewById(R.id.rename_button);
+            renameButton.setVisibility(View.VISIBLE);
+            renameButton.setOnClickListener(view -> {
+                RemoteDeviceNameDialogFragment.newInstance(mCachedDevice).show(
+                        mFragment.getFragmentManager(), RemoteDeviceNameDialogFragment.TAG);
+            });
+        }
         final ImageView imageView = mLayoutPreference.findViewById(R.id.entity_header_icon);
         if (imageView != null) {
             final Pair<Drawable, String> pair =
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
index 8d96f21..af4888b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -28,15 +28,19 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import androidx.preference.PreferenceFragmentCompat;
+
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.BasePreferenceController;
@@ -93,6 +97,8 @@
     private CachedBluetoothDevice mCachedDevice;
     @Mock
     private BluetoothAdapter mBluetoothAdapter;
+    @Mock
+    private PreferenceFragmentCompat mFragment;
     private AdvancedBluetoothDetailsHeaderController mController;
     private LayoutPreference mLayoutPreference;
 
@@ -103,7 +109,7 @@
         mContext = Robolectric.buildActivity(SettingsActivity.class).get();
         mController = new AdvancedBluetoothDetailsHeaderController(mContext, "pref_Key");
         when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
-        mController.init(mCachedDevice);
+        mController.init(mCachedDevice, mFragment);
         mLayoutPreference = new LayoutPreference(mContext,
                 LayoutInflater.from(mContext).inflate(R.layout.advanced_bt_entity_header, null));
         mController.mLayoutPreference = mLayoutPreference;
@@ -540,6 +546,22 @@
                 rightBatteryPrediction);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void enablePolishFlag_renameButtonShown() {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
+                SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+                .thenReturn("true".getBytes());
+        Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
+        when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
+
+        mController.onStart();
+
+        ImageButton button = mLayoutPreference.findViewById(R.id.rename_button);
+        assertThat(button.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
     private void assertBatteryPredictionVisible(LinearLayout linearLayout, int visible) {
         final TextView textView = linearLayout.findViewById(R.id.bt_battery_prediction);
         assertThat(textView.getVisibility()).isEqualTo(visible);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderControllerTest.java
new file mode 100644
index 0000000..d608f3f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/GeneralBluetoothDetailsHeaderControllerTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settings.flags.Flags;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowDeviceConfig;
+import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.widget.LayoutPreference;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowDeviceConfig.class})
+public class GeneralBluetoothDetailsHeaderControllerTest
+        extends BluetoothDetailsControllerTestBase {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private GeneralBluetoothDetailsHeaderController mController;
+    private LayoutPreference mPreference;
+
+    @Mock private BluetoothDevice mBluetoothDevice;
+    @Mock private LeAudioProfile mLeAudioProfile;
+
+    @Override
+    public void setUp() {
+        super.setUp();
+        FakeFeatureFactory.setupForTest();
+        android.provider.DeviceConfig.setProperty(
+                android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI,
+                SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED,
+                "true",
+                true);
+        mController =
+                new GeneralBluetoothDetailsHeaderController(
+                        mContext, mFragment, mCachedDevice, mLifecycle);
+        mPreference = new LayoutPreference(mContext, R.layout.general_bt_entity_header);
+        mPreference.setKey(mController.getPreferenceKey());
+        mScreen.addPreference(mPreference);
+        setupDevice(mDeviceConfig);
+        when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
+        when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowEntityHeaderController.reset();
+    }
+
+    /**
+     * Test to verify the current test context object works so that we are not checking null against
+     * null
+     */
+    @Test
+    public void testContextMock() {
+        assertThat(mContext.getString(com.android.settingslib.R.string.bluetooth_connected))
+                .isNotNull();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void header() {
+        when(mCachedDevice.getName()).thenReturn("device name");
+        when(mCachedDevice.getConnectionSummary()).thenReturn("Active");
+
+        showScreen(mController);
+
+        TextView deviceName = mPreference.findViewById(R.id.bt_header_device_name);
+        TextView summary = mPreference.findViewById(R.id.bt_header_connection_summary);
+        assertThat(deviceName.getText().toString()).isEqualTo("device name");
+        assertThat(summary.getText().toString()).isEqualTo("Active");
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void connectionStatusChangesWhileScreenOpen() {
+        TextView summary = mPreference.findViewById(R.id.bt_header_connection_summary);
+        when(mCachedDevice.getConnectionSummary())
+                .thenReturn(
+                        mContext.getString(com.android.settingslib.R.string.bluetooth_connected));
+
+        showScreen(mController);
+        String summaryText1 = summary.getText().toString();
+        when(mCachedDevice.getConnectionSummary()).thenReturn(null);
+        mController.onDeviceAttributesChanged();
+        String summaryText2 = summary.getText().toString();
+        when(mCachedDevice.getConnectionSummary())
+                .thenReturn(
+                        mContext.getString(com.android.settingslib.R.string.bluetooth_connecting));
+        mController.onDeviceAttributesChanged();
+        String summaryText3 = summary.getText().toString();
+
+        assertThat(summaryText1)
+                .isEqualTo(
+                        mContext.getString(com.android.settingslib.R.string.bluetooth_connected));
+        assertThat(summaryText2).isEqualTo("");
+        assertThat(summaryText3)
+                .isEqualTo(
+                        mContext.getString(com.android.settingslib.R.string.bluetooth_connecting));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void isAvailable_untetheredHeadset_returnFalse() {
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+                .thenReturn("true".getBytes());
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void isAvailable_notUntetheredHeadset_returnTrue() {
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+                .thenReturn("false".getBytes());
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void isAvailable_leAudioDevice_returnFalse() {
+        when(mCachedDevice.getUiAccessibleProfiles())
+                .thenReturn(List.of(mLeAudioProfile));
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void isAvailable_flagEnabled_returnTrue() {
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+                .thenReturn("false".getBytes());
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_BLUETOOTH_DEVICE_DETAILS_POLISH)
+    public void iaAvailable_flagDisabled_returnFalse() {
+        assertThat(mController.isAvailable()).isFalse();
+    }
+}