Merge "Make dashboard tile refresh more effcient."
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 92154be..0a8dbbf 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -15,6 +15,7 @@
  */
 package com.android.settings.dashboard;
 
+import android.content.Context;
 import android.support.v7.preference.Preference;
 
 import com.android.settingslib.drawer.DashboardCategory;
@@ -53,4 +54,10 @@
      * Returns an unique string key for the tile.
      */
     String getDashboardKeyForTile(Tile tile);
+
+    /**
+     * Returns a {@link ProgressiveDisclosureMixin} for specified fragment.
+     */
+    ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
+            DashboardFragment fragment);
 }
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index df3f6ef..ed0520a 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -72,4 +72,10 @@
         sb.append(component.getClassName());
         return sb.toString();
     }
+
+    @Override
+    public ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
+            DashboardFragment fragment) {
+        return new ProgressiveDisclosureMixin(context, this, fragment);
+    }
 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index ef49e30..9ab8cf4 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -22,7 +22,9 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -41,6 +43,7 @@
 import com.android.settingslib.drawer.SettingsDrawerActivity;
 import com.android.settingslib.drawer.Tile;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -69,7 +72,8 @@
         super.onAttach(context);
         mDashboardFeatureProvider =
                 FeatureFactory.getFactory(context).getDashboardFeatureProvider(context);
-        mProgressiveDisclosureMixin = new ProgressiveDisclosureMixin(context, this);
+        mProgressiveDisclosureMixin = mDashboardFeatureProvider
+                .getProgressiveDisclosureMixin(context, this);
         getLifecycle().addObserver(mProgressiveDisclosureMixin);
 
         final List<PreferenceController> controllers = getPreferenceControllers(context);
@@ -82,6 +86,24 @@
     }
 
     @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        // Set ComparisonCallback so we get better animation when list changes.
+        getPreferenceManager().setPreferenceComparisonCallback(
+                new PreferenceManager.SimplePreferenceComparisonCallback());
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = super.onCreateView(inflater, container, savedInstanceState);
+        if (mDashboardFeatureProvider.isEnabled()) {
+            getListView().addItemDecoration(mDividerDecoration);
+        }
+        return view;
+    }
+
+    @Override
     public void onCategoriesChanged() {
         final DashboardCategory category =
                 mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
@@ -99,6 +121,18 @@
     }
 
     @Override
+    public void setDivider(Drawable divider) {
+        if (mDashboardFeatureProvider.isEnabled()) {
+            // Intercept divider and set it transparent so system divider decoration is disabled.
+            // We will use our decoration to draw divider more intelligently.
+            mDividerDecoration.setDivider(divider);
+            super.setDivider(new ColorDrawable(Color.TRANSPARENT));
+        } else {
+            super.setDivider(divider);
+        }
+    }
+
+    @Override
     public void onStart() {
         super.onStart();
         final DashboardCategory category =
@@ -210,16 +244,6 @@
         }
     }
 
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        final View view = super.onCreateView(inflater, container, savedInstanceState);
-        if (mDashboardFeatureProvider.isEnabled()) {
-            getListView().addItemDecoration(mDividerDecoration);
-        }
-        return view;
-    }
-
     /**
      * Update state of each preference managed by PreferenceController.
      */
@@ -238,18 +262,6 @@
         }
     }
 
-    @Override
-    public void setDivider(Drawable divider) {
-        if (mDashboardFeatureProvider.isEnabled()) {
-            // Intercept divider and set it transparent so system divider decoration is disabled.
-            // We will use our decoration to draw divider more intelligently.
-            mDividerDecoration.setDivider(divider);
-            super.setDivider(new ColorDrawable(Color.TRANSPARENT));
-        } else {
-            super.setDivider(divider);
-        }
-    }
-
     /**
      * Refresh all preference items, including both static prefs from xml, and dynamic items from
      * DashboardCategory.
@@ -275,18 +287,15 @@
     /**
      * Refresh preference items backed by DashboardCategory.
      */
-    private void refreshDashboardTiles(final String TAG) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void refreshDashboardTiles(final String TAG) {
         final PreferenceScreen screen = getPreferenceScreen();
-        for (String key : mDashboardTilePrefKeys) {
-            // Remove tiles from screen
-            mProgressiveDisclosureMixin.removePreference(screen, key);
-        }
-        mDashboardTilePrefKeys.clear();
+
         final Context context = getContext();
         final DashboardCategory category =
                 mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
         if (category == null) {
-            Log.d(TAG, "NO dynamic tiles for " + TAG);
+            Log.d(TAG, "NO dashboard tiles for " + TAG);
             return;
         }
         List<Tile> tiles = category.tiles;
@@ -294,6 +303,9 @@
             Log.d(TAG, "tile list is empty, skipping category " + category.title);
             return;
         }
+        // Create a list to track which tiles are to be removed.
+        final List<String> remove = new ArrayList<>(mDashboardTilePrefKeys);
+
         // There are dashboard tiles, so we need to install SummaryLoader.
         if (mSummaryLoader != null) {
             mSummaryLoader.release();
@@ -307,32 +319,51 @@
                 Log.d(TAG, "tile does not contain a key, skipping " + tile);
                 continue;
             }
-            mDashboardTilePrefKeys.add(key);
-            final Preference pref = new DashboardTilePreference(context);
-            pref.setTitle(tile.title);
-            pref.setKey(key);
-            pref.setSummary(tile.summary);
-            if (tile.icon != null) {
-                pref.setIcon(tile.icon.loadDrawable(context));
+            if (mDashboardTilePrefKeys.contains(key)) {
+                // Have the key already, will rebind.
+                final Preference preference = mProgressiveDisclosureMixin.findPreference(
+                        screen, key);
+                bindPreferenceToTile(context, preference, tile, key);
+            } else {
+                // Don't have this key, add it.
+                final Preference pref = new DashboardTilePreference(context);
+                bindPreferenceToTile(context, pref, tile, key);
+                mProgressiveDisclosureMixin.addPreference(screen, pref);
+                mDashboardTilePrefKeys.add(key);
             }
-            final Bundle metadata = tile.metaData;
-            if (metadata != null) {
-                String clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
-                if (!TextUtils.isEmpty(clsName)) {
-                    pref.setFragment(clsName);
-                }
-            } else if (tile.intent != null) {
-                final Intent intent = new Intent(tile.intent);
-                pref.setOnPreferenceClickListener(preference -> {
-                    getActivity().startActivityForResult(intent, 0);
-                    return true;
-                });
-            }
-            // Use negated priority for order, because tile priority is based on intent-filter
-            // (larger value has higher priority). However pref order defines smaller value has
-            // higher priority.
-            pref.setOrder(-tile.priority);
-            mProgressiveDisclosureMixin.addPreference(screen, pref);
+            remove.remove(key);
         }
+        // Finally remove tiles that are gone.
+        for (String key : remove) {
+            mDashboardTilePrefKeys.remove(key);
+            mProgressiveDisclosureMixin.removePreference(screen, key);
+        }
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void bindPreferenceToTile(Context context, Preference pref, Tile tile, String key) {
+        pref.setTitle(tile.title);
+        pref.setKey(key);
+        pref.setSummary(tile.summary);
+        if (tile.icon != null) {
+            pref.setIcon(tile.icon.loadDrawable(context));
+        }
+        final Bundle metadata = tile.metaData;
+        if (metadata != null) {
+            String clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
+            if (!TextUtils.isEmpty(clsName)) {
+                pref.setFragment(clsName);
+            }
+        } else if (tile.intent != null) {
+            final Intent intent = new Intent(tile.intent);
+            pref.setOnPreferenceClickListener(preference -> {
+                getActivity().startActivityForResult(intent, 0);
+                return true;
+            });
+        }
+        // Use negated priority for order, because tile priority is based on intent-filter
+        // (larger value has higher priority). However pref order defines smaller value has
+        // higher priority.
+        pref.setOrder(-tile.priority);
     }
 }
diff --git a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
index 84b6b7f..75251b3 100644
--- a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
+++ b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
@@ -28,9 +28,9 @@
 import com.android.settings.core.lifecycle.LifecycleObserver;
 import com.android.settings.core.lifecycle.events.OnCreate;
 import com.android.settings.core.lifecycle.events.OnSaveInstanceState;
-import com.android.settings.overlay.FeatureFactory;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickListener,
@@ -43,18 +43,19 @@
     private int mTileLimit = DEFAULT_TILE_LIMIT;
 
     private final DashboardFeatureProvider mDashboardFeatureProvider;
-    private final List<Preference> collapsedPrefs = new ArrayList<>();
+    // Collapsed preference sorted by order.
+    private final List<Preference> mCollapsedPrefs = new ArrayList<>();
     private final ExpandPreference mExpandButton;
     private final PreferenceFragment mFragment;
 
     private boolean mUserExpanded;
 
-    public ProgressiveDisclosureMixin(Context context, PreferenceFragment fragment) {
+    public ProgressiveDisclosureMixin(Context context,
+            DashboardFeatureProvider dashboardFeatureProvider, PreferenceFragment fragment) {
         mFragment = fragment;
         mExpandButton = new ExpandPreference(context);
         mExpandButton.setOnPreferenceClickListener(this);
-        mDashboardFeatureProvider = FeatureFactory.getFactory(context)
-                .getDashboardFeatureProvider(context);
+        mDashboardFeatureProvider = dashboardFeatureProvider;
     }
 
     @Override
@@ -75,10 +76,10 @@
             final PreferenceScreen screen = mFragment.getPreferenceScreen();
             if (screen != null) {
                 screen.removePreference(preference);
-                for (Preference pref : collapsedPrefs) {
+                for (Preference pref : mCollapsedPrefs) {
                     screen.addPreference(pref);
                 }
-                collapsedPrefs.clear();
+                mCollapsedPrefs.clear();
                 mUserExpanded = true;
             }
         }
@@ -96,7 +97,7 @@
      * Whether the controller is in collapsed state.
      */
     public boolean isCollapsed() {
-        return !collapsedPrefs.isEmpty();
+        return !mCollapsedPrefs.isEmpty();
     }
 
     /**
@@ -115,7 +116,7 @@
         if (!shouldCollapse(screen)) {
             return;
         }
-        if (!collapsedPrefs.isEmpty()) {
+        if (!mCollapsedPrefs.isEmpty()) {
             Log.w(TAG, "collapsed list should ALWAYS BE EMPTY before collapsing!");
         }
 
@@ -134,12 +135,27 @@
     public void addPreference(PreferenceScreen screen, Preference pref) {
         // Either add to screen, or to collapsed list.
         if (isCollapsed()) {
-            // Already collapsed, add to collapsed list.
-            addToCollapsedList(pref);
+            // insert the preference to right position.
+            final int lastPreferenceIndex = screen.getPreferenceCount() - 2;
+            if (lastPreferenceIndex >= 0) {
+                final Preference lastPreference = screen.getPreference(lastPreferenceIndex);
+                if (lastPreference.getOrder() > pref.getOrder()) {
+                    // insert to screen and move the last pref to collapsed list.
+                    screen.removePreference(lastPreference);
+                    screen.addPreference(pref);
+                    addToCollapsedList(lastPreference);
+                } else {
+                    // Insert to collapsed list.
+                    addToCollapsedList(pref);
+                }
+            } else {
+                // Couldn't find last preference on screen, just add to collapsed list.
+                addToCollapsedList(pref);
+            }
         } else if (shouldCollapse(screen)) {
             // About to have too many tiles on scree, collapse and add pref to collapsed list.
+            screen.addPreference(pref);
             collapse(screen);
-            addToCollapsedList(pref);
         } else {
             // No need to collapse, add to screen directly.
             screen.addPreference(pref);
@@ -158,11 +174,11 @@
             return;
         }
         // Didn't find on screen, try removing from collapsed list.
-        for (int i = 0; i < collapsedPrefs.size(); i++) {
-            final Preference pref = collapsedPrefs.get(i);
+        for (int i = 0; i < mCollapsedPrefs.size(); i++) {
+            final Preference pref = mCollapsedPrefs.get(i);
             if (TextUtils.equals(key, pref.getKey())) {
-                collapsedPrefs.remove(pref);
-                if (collapsedPrefs.isEmpty()) {
+                mCollapsedPrefs.remove(pref);
+                if (mCollapsedPrefs.isEmpty()) {
                     // Removed last element, remove expand button too.
                     screen.removePreference(mExpandButton);
                 }
@@ -179,8 +195,8 @@
         if (preference != null) {
             return preference;
         }
-        for (int i = 0; i < collapsedPrefs.size(); i++) {
-            final Preference pref = collapsedPrefs.get(i);
+        for (int i = 0; i < mCollapsedPrefs.size(); i++) {
+            final Preference pref = mCollapsedPrefs.get(i);
             if (TextUtils.equals(key, pref.getKey())) {
                 return pref;
             }
@@ -192,9 +208,18 @@
     /**
      * Add preference to collapsed list.
      */
-    @VisibleForTesting
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     void addToCollapsedList(Preference preference) {
-        collapsedPrefs.add(preference);
+        // Insert preference based on it's order.
+        int insertionIndex = Collections.binarySearch(mCollapsedPrefs, preference);
+        if (insertionIndex < 0) {
+            insertionIndex = insertionIndex * -1 - 1;
+        }
+        mCollapsedPrefs.add(insertionIndex, preference);
     }
 
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    List<Preference> getCollapsedPrefs() {
+        return mCollapsedPrefs;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index cc064df..e4222ce 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -16,10 +16,13 @@
 package com.android.settings.dashboard;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.settings.SettingsActivity;
 import com.android.settings.TestConfig;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.overlay.FeatureFactory;
@@ -44,6 +47,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -59,6 +63,8 @@
     private DashboardCategory mDashboardCategory;
     @Mock
     private FakeFeatureFactory mFakeFeatureFactory;
+    @Mock
+    private ProgressiveDisclosureMixin mDisclosureMixin;
     private TestFragment mTestFragment;
 
     @Before
@@ -69,9 +75,12 @@
         mDashboardCategory.tiles = new ArrayList<>();
         mDashboardCategory.tiles.add(new Tile());
         mTestFragment = new TestFragment(ShadowApplication.getInstance().getApplicationContext());
-        mTestFragment.onAttach(ShadowApplication.getInstance().getApplicationContext());
+        when(mFakeFeatureFactory.dashboardFeatureProvider
+                .getProgressiveDisclosureMixin(any(Context.class), eq(mTestFragment)))
+                .thenReturn(mDisclosureMixin);
         when(mFakeFeatureFactory.dashboardFeatureProvider.getTilesForCategory(anyString()))
                 .thenReturn(mDashboardCategory);
+        mTestFragment.onAttach(ShadowApplication.getInstance().getApplicationContext());
     }
 
     @Test
@@ -87,11 +96,14 @@
 
     @Test
     public void displayTilesAsPreference_shouldAddTilesWithIntent() {
+        when(mFakeFeatureFactory.dashboardFeatureProvider.getTilesForCategory(anyString()))
+                .thenReturn(mDashboardCategory);
         when(mFakeFeatureFactory.dashboardFeatureProvider.getDashboardKeyForTile(any(Tile.class)))
                 .thenReturn("test_key");
         mTestFragment.onCreatePreferences(new Bundle(), "rootKey");
 
-        verify(mTestFragment.mScreen).addPreference(any(DashboardTilePreference.class));
+        verify(mDisclosureMixin).addPreference(any(PreferenceScreen.class),
+                any(DashboardTilePreference.class));
     }
 
     @Test
@@ -109,6 +121,27 @@
         verify(mTestFragment.mScreen, never()).addPreference(any(DashboardTilePreference.class));
     }
 
+    @Test
+    public void bindPreference_shouldBindAllData() {
+        final Preference preference = new Preference(
+                ShadowApplication.getInstance().getApplicationContext());
+        final Tile tile = new Tile();
+        tile.title = "title";
+        tile.summary = "summary";
+        tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565));
+        tile.metaData = new Bundle();
+        tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI");
+        tile.priority = 10;
+        mTestFragment.bindPreferenceToTile(mContext, preference, tile, "123");
+
+        assertThat(preference.getTitle()).isEqualTo(tile.title);
+        assertThat(preference.getSummary()).isEqualTo(tile.summary);
+        assertThat(preference.getIcon()).isNotNull();
+        assertThat(preference.getFragment())
+                .isEqualTo(tile.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS));
+        assertThat(preference.getOrder()).isEqualTo(-tile.priority);
+    }
+
     public static class TestPreferenceController extends PreferenceController {
 
         public TestPreferenceController(Context context) {
@@ -139,7 +172,6 @@
     public static class TestFragment extends DashboardFragment {
 
         private final Context mContext;
-        @Mock
         public PreferenceScreen mScreen;
 
         public TestFragment(Context context) {
diff --git a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
index 986ccd9..be02596 100644
--- a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
@@ -35,6 +35,8 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
+import java.util.List;
+
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -67,7 +69,8 @@
         mScreen = mPreferenceFragment.getPreferenceScreen();
         mAppContext = ShadowApplication.getInstance().getApplicationContext();
         mFakeFeatureFactory = (FakeFeatureFactory) FeatureFactory.getFactory(mContext);
-        mMixin = new ProgressiveDisclosureMixin(mAppContext, mPreferenceFragment);
+        mMixin = new ProgressiveDisclosureMixin(mAppContext,
+                mFakeFeatureFactory.dashboardFeatureProvider, mPreferenceFragment);
         mPreference = new Preference(mAppContext);
         mPreference.setKey("test");
         when(mFakeFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
@@ -180,4 +183,77 @@
         verify(screen, times(3)).removePreference(any(Preference.class));
     }
 
+    @Test
+    public void addToCollapsedList_shouldAddInOrder() {
+        final Preference pref1 = new Preference(mAppContext);
+        final Preference pref2 = new Preference(mAppContext);
+        pref1.setOrder(10);
+        pref2.setOrder(20);
+
+        // Pref1 has lower order than pref2, but add pref2 first. The collapsed list should maintain
+        // items in increasing order.
+        mMixin.addToCollapsedList(pref2);
+        mMixin.addToCollapsedList(pref1);
+
+        List<Preference> collapsedList = mMixin.getCollapsedPrefs();
+        assertThat(collapsedList.get(0)).isSameAs(pref1);
+        assertThat(collapsedList.get(1)).isSameAs(pref2);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_noPrefOnScreen_shouldAddToList() {
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+
+        // Just 1 preference on screen: the more button
+        when(mScreen.getPreferenceCount()).thenReturn(1);
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(100);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        // Should have 2 prefs in collapsed list now
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(2);
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_prefOrderLessThanLastOnScreen_shouldAddToScreen() {
+        final Preference lastPref = new Preference(mAppContext);
+        lastPref.setOrder(100);
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+        // 3 prefs on screen, 2 are real and the last one is more button.
+        when(mScreen.getPreferenceCount()).thenReturn(3);
+        when(mScreen.getPreference(1)).thenReturn(lastPref);
+
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(50);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        verify(mScreen).removePreference(lastPref);
+        verify(mScreen).addPreference(toBeAdded);
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(lastPref);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_prefOrderMoreThanLastOnScreen_shouldAddToList() {
+        final Preference lastPref = new Preference(mAppContext);
+        lastPref.setOrder(100);
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+        // 3 prefs on screen, 2 are real and the last one is more button.
+        when(mScreen.getPreferenceCount()).thenReturn(3);
+        when(mScreen.getPreference(1)).thenReturn(lastPref);
+
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(200);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        verify(mScreen, never()).removePreference(any(Preference.class));
+        verify(mScreen, never()).addPreference(any(Preference.class));
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded);
+    }
 }