diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 86b72ec3f94..2e4654c3994 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -96,7 +96,6 @@ public final class BluetoothDevicePreference extends GearPreference implements } mCachedDevice = cachedDevice; - mCachedDevice.registerCallback(this); mCurrentTime = System.currentTimeMillis(); mType = type; @@ -127,13 +126,24 @@ public final class BluetoothDevicePreference extends GearPreference implements @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 3d4dd29d38f..438a3815f9a 100644 --- a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java @@ -16,11 +16,13 @@ package com.android.settings.connecteddevice; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -28,6 +30,7 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater; import com.android.settings.connecteddevice.dock.DockUpdater; @@ -38,16 +41,25 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.ArrayList; +import java.util.List; + public class PreviouslyConnectedDevicePreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback { + private static final String TAG = "PreviouslyDevicePreController"; + 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 mDevicesList = new ArrayList<>(); + private final List mDockDevicesList = new ArrayList<>(); + private PreferenceGroup mPreferenceGroup; private BluetoothDeviceUpdater mBluetoothDeviceUpdater; private DockUpdater mSavedDockUpdater; - private int mPreferenceSize; private BluetoothAdapter mBluetoothAdapter; @VisibleForTesting @@ -115,17 +127,76 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc @Override public void onDeviceAdded(Preference preference) { - mPreferenceSize++; - if (mPreferenceSize <= MAX_DEVICE_NUM) { - mPreferenceGroup.addPreference(preference); + final List bluetoothDevices = + mBluetoothAdapter.getMostRecentlyConnectedDevices(); + 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()); + } } + addPreference(index, preference); updatePreferenceVisibility(); } + private void addPreference(int index, Preference preference) { + if (preference instanceof BluetoothDevicePreference) { + if (mDevicesList.size() >= index) { + mDevicesList.add(index, preference); + } else { + mDevicesList.add(preference); + } + } else { + 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()); + } + 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--; - mPreferenceGroup.removePreference(preference); + 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 e8b88f50389..d73471f94ed 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java @@ -23,8 +23,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.pm.PackageManager; @@ -34,10 +36,13 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; import com.android.settings.R; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; 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; import org.junit.Test; @@ -49,11 +54,18 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import java.util.ArrayList; +import java.util.List; + @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowBluetoothAdapter.class) public class PreviouslyConnectedDevicePreferenceControllerTest { - private final String KEY = "test_key"; + private static final String KEY = "test_key"; + private static final String FAKE_ADDRESS_1 = "AA:AA:AA:AA:AA:01"; + private static final String FAKE_ADDRESS_2 = "AA:AA:AA:AA:AA:02"; + private static final String FAKE_ADDRESS_3 = "AA:AA:AA:AA:AA:03"; + private static final String FAKE_ADDRESS_4 = "AA:AA:AA:AA:AA:04"; @Mock private DashboardFragment mDashboardFragment; @@ -67,6 +79,22 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { private PreferenceManager mPreferenceManager; @Mock private Preference mSeeAllPreference; + @Mock + private CachedBluetoothDevice mCachedDevice1; + @Mock + private CachedBluetoothDevice mCachedDevice2; + @Mock + private CachedBluetoothDevice mCachedDevice3; + @Mock + private CachedBluetoothDevice mCachedDevice4; + @Mock + private BluetoothDevice mBluetoothDevice1; + @Mock + private BluetoothDevice mBluetoothDevice2; + @Mock + private BluetoothDevice mBluetoothDevice3; + @Mock + private BluetoothDevice mBluetoothDevice4; private Context mContext; private PreviouslyConnectedDevicePreferenceController mPreConnectedDeviceController; @@ -85,6 +113,22 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { mPreConnectedDeviceController.setSavedDockUpdater(mDockUpdater); mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); + when(mCachedDevice1.getAddress()).thenReturn(FAKE_ADDRESS_1); + when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); + when(mCachedDevice2.getAddress()).thenReturn(FAKE_ADDRESS_2); + when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); + when(mCachedDevice3.getAddress()).thenReturn(FAKE_ADDRESS_3); + when(mCachedDevice4.getDevice()).thenReturn(mBluetoothDevice4); + when(mCachedDevice4.getAddress()).thenReturn(FAKE_ADDRESS_4); + + final List mMostRecentlyConnectedDevices = new ArrayList<>(); + mMostRecentlyConnectedDevices.add(mBluetoothDevice1); + mMostRecentlyConnectedDevices.add(mBluetoothDevice2); + mMostRecentlyConnectedDevices.add(mBluetoothDevice4); + mMostRecentlyConnectedDevices.add(mBluetoothDevice3); + mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(mMostRecentlyConnectedDevices); + mPreferenceGroup = spy(new PreferenceCategory(mContext)); doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager(); mPreferenceGroup.setVisible(false); @@ -136,29 +180,60 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { @Test public void onDeviceAdded_addDevicePreference_displayIt() { - mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext)); + final BluetoothDevicePreference preference1 = new BluetoothDevicePreference( + mContext, mCachedDevice1, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT); - assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1); + mPreConnectedDeviceController.onDeviceAdded(preference1); + + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2); + } + + @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() { - mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext)); - mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext)); - mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext)); - mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext)); + final BluetoothDevicePreference preference1 = new BluetoothDevicePreference( + mContext, mCachedDevice1, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference2 = new BluetoothDevicePreference( + mContext, mCachedDevice2, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference3 = new BluetoothDevicePreference( + 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 */); - assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(3); + 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); } @Test - public void onDeviceRemoved_removeLastDevice_setInvisible() { - final Preference preference = new Preference(mContext); - mPreferenceGroup.addPreference(preference); + 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(preference); + mPreConnectedDeviceController.onDeviceRemoved(preference1); + mPreConnectedDeviceController.onDeviceRemoved(dockPreference); - assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0); + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1); } @Test diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java index f65729366cf..9de5c7fc2da 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java @@ -17,6 +17,7 @@ package com.android.settings.testutils.shadow; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -29,6 +30,7 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto private int mState; private List mSupportedProfiles = new ArrayList<>(); + private List mMostRecentlyConnectedDevices = new ArrayList<>(); @Implementation protected List getSupportedProfiles() { @@ -56,4 +58,13 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto protected boolean factoryReset() { return true; } + + @Implementation + protected List getMostRecentlyConnectedDevices() { + return mMostRecentlyConnectedDevices; + } + + public void setMostRecentlyConnectedDevices(List list) { + mMostRecentlyConnectedDevices = list; + } }