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

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

Merge "Implement the collapsible feature of conditional card"

parents 92b6f1b6 da1ffe88
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -24,10 +24,14 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.homepage.contextualcards.ContextualCard.CardType;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.conditional
        .ConditionHeaderContextualCardRenderer;
import com.android.settings.homepage.contextualcards.legacysuggestion
        .LegacySuggestionContextualCardController;
import com.android.settings.homepage.contextualcards.legacysuggestion
        .LegacySuggestionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.conditional
        .ConditionFooterContextualCardRenderer;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;

@@ -83,6 +87,14 @@ public class ContextualCardLookupTable {
                        SliceContextualCardRenderer.VIEW_TYPE,
                        SliceContextualCardController.class,
                        SliceContextualCardRenderer.class));
                add(new ControllerRendererMapping(CardType.CONDITIONAL_FOOTER,
                        ConditionFooterContextualCardRenderer.VIEW_TYPE,
                        ConditionContextualCardController.class,
                        ConditionFooterContextualCardRenderer.class));
                add(new ControllerRendererMapping(CardType.CONDITIONAL_HEADER,
                        ConditionHeaderContextualCardRenderer.VIEW_TYPE,
                        ConditionContextualCardController.class,
                        ConditionHeaderContextualCardRenderer.class));
            }};

    public static Class<? extends ContextualCardController> getCardControllerClass(
+2 −0
Original line number Diff line number Diff line
@@ -129,5 +129,7 @@ public class ContextualCardsAdapter extends RecyclerView.Adapter<RecyclerView.Vi
            // Adding items to empty list, should animate.
            mRecyclerView.scheduleLayoutAnimation();
        }

        //TODO(b/119465242): flickering conditional cards after collapsing/expanding
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -26,10 +26,14 @@ import androidx.lifecycle.LifecycleOwner;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.conditional
        .ConditionHeaderContextualCardRenderer;
import com.android.settings.homepage.contextualcards.legacysuggestion
        .LegacySuggestionContextualCardController;
import com.android.settings.homepage.contextualcards.legacysuggestion
        .LegacySuggestionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.conditional
        .ConditionFooterContextualCardRenderer;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;

@@ -131,6 +135,12 @@ public class ControllerRendererPool {
        } else if (LegacySuggestionContextualCardRenderer.class == clz) {
            return new LegacySuggestionContextualCardRenderer(context,
                    this /* controllerRendererPool */);
        } else if (ConditionFooterContextualCardRenderer.class == clz) {
            return new ConditionFooterContextualCardRenderer(context,
                    this /*controllerRendererPool*/);
        } else if (ConditionHeaderContextualCardRenderer.class == clz) {
            return new ConditionHeaderContextualCardRenderer(context,
                    this /*controllerRendererPool*/);
        }
        return null;
    }
+100 −9
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.settings.homepage.contextualcards.conditional;
import android.content.Context;
import android.util.ArrayMap;

import androidx.annotation.VisibleForTesting;

import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardController;
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
@@ -26,8 +28,11 @@ 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.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * This controller triggers the loading of conditional cards and monitors state changes to
@@ -35,8 +40,12 @@ import java.util.Map;
 */
public class ConditionContextualCardController implements ContextualCardController,
        ConditionListener, LifecycleObserver, OnStart, OnStop {
    public static final int EXPANDING_THRESHOLD = 2;

    private static final double UNSUPPORTED_RANKING = -99999.0;
    private static final String TAG = "ConditionCtxCardCtrl";
    private static final String CONDITION_FOOTER = "condition_footer";
    private static final String CONDITION_HEADER = "condition_header";

    private final Context mContext;
    private final ConditionManager mConditionManager;
@@ -93,20 +102,102 @@ public class ConditionContextualCardController implements ContextualCardControll

    @Override
    public void onConditionsChanged() {
        if (mListener == null) {
            return;
        }
        final List<ContextualCard> conditionCards = mConditionManager.getDisplayableCards();
        final Map<Integer, List<ContextualCard>> conditionalCards =
                buildConditionalCardsWithFooterOrHeader(conditionCards);
        mListener.onContextualCardUpdated(conditionalCards);

        final boolean isOddNumber = conditionCards.size() % 2 == 1;
        if (isOddNumber) {
            final int lastIndex = conditionCards.size() - 1;
            final ConditionalContextualCard card = (ConditionalContextualCard) conditionCards
                    .get(lastIndex);
            conditionCards.set(lastIndex, card.mutate().setIsHalfWidth(false).build());
    }

        if (mListener != null) {
    /**
     * According to conditional cards, build a map that includes conditional cards, header card and
     * footer card.
     *
     * Rules:
     * - The last one of conditional cards will be displayed as a full-width card if the size of
     * conditional cards is odd number. The rest will be displayed as a half-width card.
     * - By default conditional cards will be collapsed if there are more than TWO cards.
     *
     * For examples:
     * - Only one conditional card: Returns a map that contains a full-width conditional card,
     * no header card and no footer card.
     * <p>Map{(CONDITIONAL, conditionCards), (CONDITIONAL_FOOTER, EMPTY_LIST), (CONDITIONAL_HEADER,
     * EMPTY_LIST)}</p>
     * - Two conditional cards: Returns a map that contains two half-width conditional cards,
     * no header card and no footer card.
     * <p>Map{(CONDITIONAL, conditionCards), (CONDITIONAL_FOOTER, EMPTY_LIST), (CONDITIONAL_HEADER,
     * EMPTY_LIST)}</p>
     * - Three conditional cards or above: By default, returns a map that contains no conditional
     * card, one header card and no footer card. If conditional cards are expanded, will returns a
     * map that contains three conditional cards, no header card and one footer card.
     * If expanding conditional cards:
     * <p>Map{(CONDITIONAL, conditionCards), (CONDITIONAL_FOOTER, footerCards), (CONDITIONAL_HEADER,
     * EMPTY_LIST)}</p>
     * If collapsing conditional cards:
     * <p>Map{(CONDITIONAL, EMPTY_LIST), (CONDITIONAL_FOOTER, EMPTY_LIST), (CONDITIONAL_HEADER,
     * headerCards)}</p>
     *
     * @param conditionCards A list of conditional cards that are from {@link
     * ConditionManager#getDisplayableCards}
     * @return A map contained three types of lists
     */
    @VisibleForTesting
    Map<Integer, List<ContextualCard>> buildConditionalCardsWithFooterOrHeader(
            List<ContextualCard> conditionCards) {
        final Map<Integer, List<ContextualCard>> conditionalCards = new ArrayMap<>();
            conditionalCards.put(ContextualCard.CardType.CONDITIONAL, conditionCards);
            mListener.onContextualCardUpdated(conditionalCards);
        conditionalCards.put(ContextualCard.CardType.CONDITIONAL,
                getExpandedConditionalCards(conditionCards));
        conditionalCards.put(ContextualCard.CardType.CONDITIONAL_FOOTER,
                getConditionalFooterCard(conditionCards));
        conditionalCards.put(ContextualCard.CardType.CONDITIONAL_HEADER,
                getConditionalHeaderCard(conditionCards));
        return conditionalCards;
    }

    private List<ContextualCard> getExpandedConditionalCards(List<ContextualCard> conditionCards) {
        if (conditionCards.isEmpty() || (conditionCards.size() > EXPANDING_THRESHOLD
                && !mIsExpanded)) {
            return Collections.EMPTY_LIST;
        }
        final List<ContextualCard> expandedCards = conditionCards.stream().collect(
                Collectors.toList());
        final boolean isOddNumber = expandedCards.size() % 2 == 1;
        if (isOddNumber) {
            final int lastIndex = expandedCards.size() - 1;
            final ConditionalContextualCard card =
                    (ConditionalContextualCard) expandedCards.get(lastIndex);
            expandedCards.set(lastIndex, card.mutate().setIsHalfWidth(false).build());
        }
        return expandedCards;
    }

    private List<ContextualCard> getConditionalFooterCard(List<ContextualCard> conditionCards) {
        if (!conditionCards.isEmpty() && mIsExpanded
                && conditionCards.size() > EXPANDING_THRESHOLD) {
            final List<ContextualCard> footerCards = new ArrayList<>();
            footerCards.add(new ConditionFooterContextualCard.Builder()
                    .setName(CONDITION_FOOTER)
                    .setRankingScore(UNSUPPORTED_RANKING)
                    .build());
            return footerCards;
        }
        return Collections.EMPTY_LIST;
    }

    private List<ContextualCard> getConditionalHeaderCard(List<ContextualCard> conditionCards) {
        if (!conditionCards.isEmpty() && !mIsExpanded
                && conditionCards.size() > EXPANDING_THRESHOLD) {
            final List<ContextualCard> headerCards = new ArrayList<>();
            headerCards.add(new ConditionHeaderContextualCard.Builder()
                    .setConditionalCards(conditionCards)
                    .setName(CONDITION_HEADER)
                    .setRankingScore(UNSUPPORTED_RANKING)
                    .build());
            return headerCards;
        }
        return Collections.EMPTY_LIST;
    }
}
+22 −0
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.settings.homepage.contextualcards.conditional;

import android.text.TextUtils;

import com.android.settings.homepage.contextualcards.ContextualCard;

import java.util.List;
import java.util.Objects;

/**
 * Data class representing a condition header {@link ContextualCard}.
@@ -44,6 +47,25 @@ public class ConditionHeaderContextualCard extends ContextualCard {
        return mConditionalCards;
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), mConditionalCards);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof ConditionHeaderContextualCard)) {
            return false;
        }
        final ConditionHeaderContextualCard that = (ConditionHeaderContextualCard) obj;

        return TextUtils.equals(getName(), that.getName()) && mConditionalCards.equals(
                that.mConditionalCards);
    }

    public static class Builder extends ContextualCard.Builder {

        private List<ContextualCard> mConditionalCards;