Fix settings crash

- This CL before, "Previously connected device" didn't
  handle dock device. If user have disconnected dock
  device will cause Settings crash.

  This CL add condition to handle dock device to avoid crash.
- Update test case.

Bug: 157653997
Bug: 167054620
Test: make -j42 RunSettingsRoboTests
Change-Id: I769cee3f589e14a993b00a0ae6ec3ddfba8ef281
Merged-In: I769cee3f589e14a993b00a0ae6ec3ddfba8ef281
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 86b72ec..2e4654c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -96,7 +96,6 @@
         }
 
         mCachedDevice = cachedDevice;
-        mCachedDevice.registerCallback(this);
         mCurrentTime = System.currentTimeMillis();
         mType = type;
 
@@ -127,13 +126,24 @@
     @Override
     protected void onPrepareForRemoval() {
         super.onPrepareForRemoval();
-        mCachedDevice.unregisterCallback(this);
         if (mDisconnectDialog != null) {
             mDisconnectDialog.dismiss();
             mDisconnectDialog = null;
         }
     }
 
+    @Override
+    public void onAttached() {
+        super.onAttached();
+        mCachedDevice.registerCallback(this);
+    }
+
+    @Override
+    public void onDetached() {
+        super.onDetached();
+        mCachedDevice.unregisterCallback(this);
+    }
+
     public CachedBluetoothDevice getBluetoothDevice() {
         return mCachedDevice;
     }
diff --git a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
index 78791d4..438a381 100644
--- a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
@@ -51,14 +51,15 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int MAX_DEVICE_NUM = 3;
+    private static final int DOCK_DEVICE_INDEX = 9;
     private static final String KEY_SEE_ALL = "previously_connected_devices_see_all";
 
     private final List<Preference> mDevicesList = new ArrayList<>();
+    private final List<Preference> mDockDevicesList = new ArrayList<>();
 
     private PreferenceGroup mPreferenceGroup;
     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
     private DockUpdater mSavedDockUpdater;
-    private int mPreferenceSize;
     private BluetoothAdapter mBluetoothAdapter;
 
     @VisibleForTesting
@@ -126,33 +127,38 @@
 
     @Override
     public void onDeviceAdded(Preference preference) {
-        mPreferenceSize++;
         final List<BluetoothDevice> bluetoothDevices =
                 mBluetoothAdapter.getMostRecentlyConnectedDevices();
-        final int index = bluetoothDevices.indexOf(((BluetoothDevicePreference) preference)
-                .getBluetoothDevice().getDevice());
+        final int index = preference instanceof BluetoothDevicePreference
+                ? bluetoothDevices.indexOf(((BluetoothDevicePreference) preference)
+                .getBluetoothDevice().getDevice()) : DOCK_DEVICE_INDEX;
         if (DEBUG) {
             Log.d(TAG, "onDeviceAdded() " + preference.getTitle() + ", index of : " + index);
             for (BluetoothDevice device : bluetoothDevices) {
                 Log.d(TAG, "onDeviceAdded() most recently device : " + device.getName());
             }
         }
-        if (mPreferenceSize <= MAX_DEVICE_NUM) {
-            addPreference(mPreferenceSize, index, preference);
-        } else {
-            addPreference(MAX_DEVICE_NUM, index, preference);
-        }
+        addPreference(index, preference);
         updatePreferenceVisibility();
     }
 
-    private void addPreference(int size, int index, Preference preference) {
-        if (mDevicesList.size() >= index) {
-            mDevicesList.add(index, preference);
+    private void addPreference(int index, Preference preference) {
+        if (preference instanceof BluetoothDevicePreference) {
+            if (mDevicesList.size() >= index) {
+                mDevicesList.add(index, preference);
+            } else {
+                mDevicesList.add(preference);
+            }
         } else {
-            mDevicesList.add(preference);
+            mDockDevicesList.add(preference);
         }
+        addPreference();
+    }
+
+    private void addPreference() {
         mPreferenceGroup.removeAll();
         mPreferenceGroup.addPreference(mSeeAllPreference);
+        final int size = getDeviceListSize();
         for (int i = 0; i < size; i++) {
             if (DEBUG) {
                 Log.d(TAG, "addPreference() add device : " + mDevicesList.get(i).getTitle());
@@ -160,23 +166,37 @@
             mDevicesList.get(i).setOrder(i);
             mPreferenceGroup.addPreference(mDevicesList.get(i));
         }
+        if (mDockDevicesList.size() > 0) {
+            for (int i = 0; i < getDockDeviceListSize(MAX_DEVICE_NUM - size); i++) {
+                if (DEBUG) {
+                    Log.d(TAG, "addPreference() add dock device : "
+                            + mDockDevicesList.get(i).getTitle());
+                }
+                mDockDevicesList.get(i).setOrder(DOCK_DEVICE_INDEX);
+                mPreferenceGroup.addPreference(mDockDevicesList.get(i));
+            }
+        }
+    }
+
+    private int getDeviceListSize() {
+        return mDevicesList.size() >= MAX_DEVICE_NUM
+                ? MAX_DEVICE_NUM : mDevicesList.size();
+    }
+
+    private int getDockDeviceListSize(int availableSize) {
+        return mDockDevicesList.size() >= availableSize
+                ? availableSize : mDockDevicesList.size();
     }
 
     @Override
     public void onDeviceRemoved(Preference preference) {
-        mPreferenceSize--;
-        mDevicesList.remove(preference);
-        mPreferenceGroup.removeAll();
-        mPreferenceGroup.addPreference(mSeeAllPreference);
-        final int size = mDevicesList.size() >= MAX_DEVICE_NUM
-                ? MAX_DEVICE_NUM : mDevicesList.size();
-        for (int i = 0; i < size; i++) {
-            if (DEBUG) {
-                Log.d(TAG, "onDeviceRemoved() add device : " + mDevicesList.get(i).getTitle());
-            }
-            mDevicesList.get(i).setOrder(i);
-            mPreferenceGroup.addPreference(mDevicesList.get(i));
+        if (preference instanceof BluetoothDevicePreference) {
+            mDevicesList.remove(preference);
+        } else {
+            mDockDevicesList.remove(preference);
         }
+
+        addPreference();
         updatePreferenceVisibility();
     }
 
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
index 3363ff5..d73471f 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
@@ -41,6 +41,7 @@
 import com.android.settings.connecteddevice.dock.DockUpdater;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.widget.SingleTargetGearPreference;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.Before;
@@ -188,6 +189,16 @@
     }
 
     @Test
+    public void onDeviceAdded_addDockDevicePreference_displayIt() {
+        final SingleTargetGearPreference dockPreference = new SingleTargetGearPreference(
+                mContext, null /* AttributeSet */);
+
+        mPreConnectedDeviceController.onDeviceAdded(dockPreference);
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
+    }
+
+    @Test
     public void onDeviceAdded_addFourDevicePreference_onlyDisplayThree() {
         final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(
                 mContext, mCachedDevice1, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
@@ -197,11 +208,14 @@
                 mContext, mCachedDevice3, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
         final BluetoothDevicePreference preference4 = new BluetoothDevicePreference(
                 mContext, mCachedDevice4, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+        final SingleTargetGearPreference dockPreference = new SingleTargetGearPreference(
+                mContext, null /* AttributeSet */);
 
         mPreConnectedDeviceController.onDeviceAdded(preference1);
         mPreConnectedDeviceController.onDeviceAdded(preference2);
         mPreConnectedDeviceController.onDeviceAdded(preference3);
         mPreConnectedDeviceController.onDeviceAdded(preference4);
+        mPreConnectedDeviceController.onDeviceAdded(dockPreference);
 
         // 3 BluetoothDevicePreference and 1 see all preference
         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4);
@@ -211,9 +225,13 @@
     public void onDeviceRemoved_removeLastDevice_showSeeAllPreference() {
         final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(
                 mContext, mCachedDevice1, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+        final SingleTargetGearPreference dockPreference = new SingleTargetGearPreference(
+                mContext, null /* AttributeSet */);
         mPreferenceGroup.addPreference(preference1);
+        mPreferenceGroup.addPreference(dockPreference);
 
         mPreConnectedDeviceController.onDeviceRemoved(preference1);
+        mPreConnectedDeviceController.onDeviceRemoved(dockPreference);
 
         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
     }