Add intent action for BT device detail page

Also update detail page to accept cold start:
1. Check whether profile is ready
2. When it is ready, refresh UI

Bug: 123665527
Test: SettingsRoboTests
Change-Id: I39382fd97e9da46fca08cd2e4a3ef15d32703664
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 90aa55f..e0910f2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2987,6 +2987,18 @@
                        android:value="true" />
         </activity>
 
+        <activity android:name="Settings$BluetoothDeviceDetailActivity"
+                  android:label="@string/device_details_title"
+                  android:permission="android.permission.BLUETOOTH_PRIVILEGED"
+                  android:parentActivityName="Settings$ConnectedDeviceDashboardActivity">
+            <intent-filter android:priority="1">
+                <action android:name="com.android.settings.BLUETOOTH_DEVICE_DETAIL_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.bluetooth.BluetoothDeviceDetailsFragment" />
+        </activity>
+
         <activity android:name=".panel.SettingsPanelActivity"
             android:label="@string/settings_panel_title"
             android:theme="@style/Theme.BottomDialog"
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index e7f543a..ae4ae2a 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -156,6 +156,7 @@
     }
     public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
     public static class AdvancedConnectedDeviceActivity extends SettingsActivity { /* empty */ }
+    public static class BluetoothDeviceDetailActivity extends SettingsActivity { /* empty */ }
 
     // Top level categories for new IA
     public static class NetworkDashboardActivity extends SettingsActivity {}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 5c609e6..749a38f 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -45,7 +45,8 @@
  * supports, such as "Phone audio", "Media audio", "Contact sharing", etc.
  */
 public class BluetoothDetailsProfilesController extends BluetoothDetailsController
-        implements Preference.OnPreferenceClickListener {
+        implements Preference.OnPreferenceClickListener,
+        LocalBluetoothProfileManager.ServiceListener {
     private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
 
     @VisibleForTesting
@@ -87,6 +88,7 @@
         pref.setKey(profile.toString());
         pref.setTitle(profile.getNameResource(mCachedDevice.getDevice()));
         pref.setOnPreferenceClickListener(this);
+        pref.setOrder(profile.getOrdinal());
         return pref;
     }
 
@@ -221,7 +223,7 @@
         }
         BluetoothDevice device = mCachedDevice.getDevice();
         A2dpProfile a2dp = (A2dpProfile) profile;
-        if (a2dp.supportsHighQualityAudio(device)) {
+        if (a2dp.isProfileReady() && a2dp.supportsHighQualityAudio(device)) {
             SwitchPreference highQualityAudioPref = new SwitchPreference(
                     mProfilesContainer.getContext());
             highQualityAudioPref.setKey(HIGH_QUALITY_AUDIO_PREF_TAG);
@@ -235,6 +237,28 @@
         }
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+        mProfileManager.removeServiceListener(this);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mProfileManager.addServiceListener(this);
+    }
+
+    @Override
+    public void onServiceConnected() {
+        refresh();
+    }
+
+    @Override
+    public void onServiceDisconnected() {
+        refresh();
+    }
+
     /**
      * Refreshes the state of the switches for all profiles, possibly adding or removing switches as
      * needed.
@@ -242,7 +266,10 @@
     @Override
     protected void refresh() {
         for (LocalBluetoothProfile profile : getProfiles()) {
-            SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(
+            if (!profile.isProfileReady()) {
+                continue;
+            }
+            SwitchPreference pref = mProfilesContainer.findPreference(
                     profile.toString());
             if (pref == null) {
                 pref = createProfilePreference(mProfilesContainer.getContext(), profile);
@@ -252,7 +279,7 @@
             refreshProfilePreference(pref, profile);
         }
         for (LocalBluetoothProfile removedProfile : mCachedDevice.getRemovedProfiles()) {
-            SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(
+            final SwitchPreference pref = mProfilesContainer.findPreference(
                     removedProfile.toString());
             if (pref != null) {
                 mProfilesContainer.removePreference(pref);
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 98455f2..2fbd061 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -107,6 +107,11 @@
         mDeviceAddress = getArguments().getString(KEY_DEVICE_ADDRESS);
         mManager = getLocalBluetoothManager(context);
         mCachedDevice = getCachedDevice(mDeviceAddress);
+        if (mCachedDevice == null) {
+            // Close this page if device is null with invalid device mac address
+            finish();
+            return;
+        }
         super.onAttach(context);
         use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
index 9577fa7..57fd86b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
@@ -294,6 +294,7 @@
         PbapServerProfile psp = mock(PbapServerProfile.class);
         when(psp.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_pbap);
         when(psp.toString()).thenReturn(PbapServerProfile.NAME);
+        when(psp.isProfileReady()).thenReturn(true);
         when(mProfileManager.getPbapProfile()).thenReturn(psp);
 
         showScreen(mController);
@@ -316,6 +317,7 @@
         PbapServerProfile psp = mock(PbapServerProfile.class);
         when(psp.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_pbap);
         when(psp.toString()).thenReturn(PbapServerProfile.NAME);
+        when(psp.isProfileReady()).thenReturn(true);
         when(mProfileManager.getPbapProfile()).thenReturn(psp);
 
         showScreen(mController);
@@ -336,6 +338,7 @@
         setupDevice(makeDefaultDeviceConfig());
         MapProfile mapProfile = mock(MapProfile.class);
         when(mapProfile.getNameResource(mDevice)).thenReturn(R.string.bluetooth_profile_map);
+        when(mapProfile.isProfileReady()).thenReturn(true);
         when(mProfileManager.getMapProfile()).thenReturn(mapProfile);
         when(mProfileManager.getProfileByName(eq(mapProfile.toString()))).thenReturn(mapProfile);
         mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
@@ -361,6 +364,7 @@
         when(profile.supportsHighQualityAudio(mDevice)).thenReturn(supportsHighQualityAudio);
         when(profile.isHighQualityAudioEnabled(mDevice)).thenReturn(highQualityAudioEnabled);
         when(profile.isPreferred(mDevice)).thenReturn(preferred);
+        when(profile.isProfileReady()).thenReturn(true);
         mConnectableProfiles.add(profile);
         return profile;
     }
@@ -442,12 +446,25 @@
         setupDevice(makeDefaultDeviceConfig());
         A2dpProfile audioProfile = addMockA2dpProfile(false, true, true);
         showScreen(mController);
-        SwitchPreference audioPref =
-            (SwitchPreference) mScreen.findPreference(audioProfile.toString());
+        SwitchPreference audioPref = mScreen.findPreference(audioProfile.toString());
         SwitchPreference highQualityAudioPref = getHighQualityAudioPref();
         assertThat(audioPref).isNotNull();
         assertThat(audioPref.isChecked()).isFalse();
         assertThat(highQualityAudioPref).isNotNull();
         assertThat(highQualityAudioPref.isVisible()).isFalse();
     }
+
+    @Test
+    public void onResume_addServiceListener() {
+        mController.onResume();
+
+        verify(mProfileManager).addServiceListener(mController);
+    }
+
+    @Test
+    public void onPause_removeServiceListener() {
+        mController.onPause();
+
+        verify(mProfileManager).removeServiceListener(mController);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java b/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java
index 4ed04f0..aec6dd2 100644
--- a/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java
+++ b/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java
@@ -70,16 +70,16 @@
 
         BluetoothDeviceDetailsFragment.sTestDataFactory =
                 new BluetoothDeviceDetailsFragment.TestDataFactory() {
-            @Override
-            public CachedBluetoothDevice getDevice(String deviceAddress) {
-                return mCachedDevice;
-            }
+                    @Override
+                    public CachedBluetoothDevice getDevice(String deviceAddress) {
+                        return mCachedDevice;
+                    }
 
-            @Override
-            public LocalBluetoothManager getManager(Context context) {
-                return mBluetoothManager;
-            }
-        };
+                    @Override
+                    public LocalBluetoothManager getManager(Context context) {
+                        return mBluetoothManager;
+                    }
+                };
     }
 
     @Test
@@ -103,4 +103,4 @@
             throw new RuntimeException(e);
         }
     }
-}
+}
\ No newline at end of file