Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ec79681 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make dashboard tile refresh more effcient."

parents 1d308568 a1a84e65
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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 @@ public interface DashboardFeatureProvider {
     * 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);
}
+6 −0
Original line number Diff line number Diff line
@@ -72,4 +72,10 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
        sb.append(component.getClassName());
        return sb.toString();
    }

    @Override
    public ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
            DashboardFragment fragment) {
        return new ProgressiveDisclosureMixin(context, this, fragment);
    }
}
+85 −54
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import android.graphics.Color;
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.DashboardCategory;
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 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        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);
@@ -81,6 +85,24 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        }
    }

    @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 =
@@ -98,6 +120,18 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        refreshAllPreferences(getLogTag());
    }

    @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();
@@ -210,16 +244,6 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        }
    }

    @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 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        }
    }

    @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 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
    /**
     * 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 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
            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,8 +319,29 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
                Log.d(TAG, "tile does not contain a key, skipping " + tile);
                continue;
            }
            mDashboardTilePrefKeys.add(key);
            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);
            }
            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);
@@ -332,7 +365,5 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
        // (larger value has higher priority). However pref order defines smaller value has
        // higher priority.
        pref.setOrder(-tile.priority);
            mProgressiveDisclosureMixin.addPreference(screen, pref);
        }
    }
}
+45 −20
Original line number Diff line number Diff line
@@ -28,9 +28,9 @@ import android.util.Log;
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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
    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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
            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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
     * Whether the controller is in collapsed state.
     */
    public boolean isCollapsed() {
        return !collapsedPrefs.isEmpty();
        return !mCollapsedPrefs.isEmpty();
    }

    /**
@@ -115,7 +116,7 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
        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 class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
    public void addPreference(PreferenceScreen screen, Preference pref) {
        // Either add to screen, or to collapsed list.
        if (isCollapsed()) {
            // Already collapsed, add to collapsed list.
            // 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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
            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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
        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 @@ public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickL
    /**
     * 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;
    }
}
+35 −3
Original line number Diff line number Diff line
@@ -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 java.util.List;
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 @@ public class DashboardFragmentTest {
    private DashboardCategory mDashboardCategory;
    @Mock
    private FakeFeatureFactory mFakeFeatureFactory;
    @Mock
    private ProgressiveDisclosureMixin mDisclosureMixin;
    private TestFragment mTestFragment;

    @Before
@@ -69,9 +75,12 @@ public class DashboardFragmentTest {
        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 @@ public class DashboardFragmentTest {

    @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 @@ public class DashboardFragmentTest {
        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 class DashboardFragmentTest {
    public static class TestFragment extends DashboardFragment {

        private final Context mContext;
        @Mock
        public PreferenceScreen mScreen;

        public TestFragment(Context context) {
Loading