blob: 02b82b9e71320d8318256d26e2b86a33c2a0c176 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard;
import android.annotation.ColorInt;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
import com.android.settings.SettingsActivity;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapter;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settings.dashboard.suggestions.SuggestionAdapter;
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.suggestions.SuggestionParser;
import java.util.ArrayList;
import java.util.List;
public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder>
implements SummaryLoader.SummaryConsumer {
public static final String TAG = "DashboardAdapter";
private static final String STATE_SUGGESTION_LIST = "suggestion_list";
private static final String STATE_CATEGORY_LIST = "category_list";
private static final String STATE_SUGGESTION_MODE = "suggestion_mode";
private static final String STATE_SUGGESTIONS_SHOWN_LOGGED = "suggestions_shown_logged";
private static final int DONT_SET_BACKGROUND_ATTR = -1;
private static final String STATE_SUGGESTION_CONDITION_MODE = "suggestion_condition_mode";
private final IconCache mCache;
private final Context mContext;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final DashboardFeatureProvider mDashboardFeatureProvider;
private final SuggestionFeatureProvider mSuggestionFeatureProvider;
private final ArrayList<String> mSuggestionsShownLogged;
private boolean mFirstFrameDrawn;
private boolean mCombineSuggestionAndCondition;
private RecyclerView mRecyclerView;
private SuggestionParser mSuggestionParser;
private SuggestionAdapter mSuggestionAdapter;
private SuggestionDismissController mSuggestionDismissHandler;
private SuggestionDismissController.Callback mCallback;
@VisibleForTesting
DashboardData mDashboardData;
private View.OnClickListener mTileClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO: get rid of setTag/getTag
mDashboardFeatureProvider.openTileIntent((Activity) mContext, (Tile) v.getTag());
}
};
private View.OnClickListener mConditionClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mCombineSuggestionAndCondition) {
Condition condition = (Condition) v.getTag();
//TODO: get rid of setTag/getTag
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
condition.getMetricsConstant());
condition.onPrimaryClick();
} else {
Condition expandedCondition = mDashboardData.getExpandedCondition();
//TODO: get rid of setTag/getTag
if (v.getTag() == expandedCondition) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
expandedCondition.getMetricsConstant());
expandedCondition.onPrimaryClick();
} else {
expandedCondition = (Condition) v.getTag();
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND,
expandedCondition.getMetricsConstant());
updateExpandedCondition(expandedCondition);
}
}
}
};
@Deprecated
public DashboardAdapter(Context context, Bundle savedInstanceState,
List<Condition> conditions) {
this(context, savedInstanceState, conditions, null, null);
}
public DashboardAdapter(Context context, Bundle savedInstanceState,
List<Condition> conditions, SuggestionParser suggestionParser,
SuggestionDismissController.Callback callback) {
List<Tile> suggestions = null;
List<DashboardCategory> categories = null;
int suggestionMode = DashboardData.SUGGESTION_MODE_DEFAULT;
int suggestionConditionMode = DashboardData.HEADER_MODE_DEFAULT;
mContext = context;
final FeatureFactory factory = FeatureFactory.getFactory(context);
mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
mDashboardFeatureProvider = factory.getDashboardFeatureProvider(context);
mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context);
mCombineSuggestionAndCondition = mDashboardFeatureProvider.combineSuggestionAndCondition();
mCache = new IconCache(context);
mSuggestionParser = suggestionParser;
mCallback = callback;
setHasStableIds(true);
if (savedInstanceState != null) {
suggestions = savedInstanceState.getParcelableArrayList(STATE_SUGGESTION_LIST);
categories = savedInstanceState.getParcelableArrayList(STATE_CATEGORY_LIST);
suggestionConditionMode = savedInstanceState.getInt(
STATE_SUGGESTION_CONDITION_MODE, suggestionConditionMode);
suggestionMode = savedInstanceState.getInt(
STATE_SUGGESTION_MODE, DashboardData.SUGGESTION_MODE_DEFAULT);
mSuggestionsShownLogged = savedInstanceState.getStringArrayList(
STATE_SUGGESTIONS_SHOWN_LOGGED);
} else {
mSuggestionsShownLogged = new ArrayList<>();
}
mDashboardData = new DashboardData.Builder()
.setConditions(conditions)
.setSuggestions(suggestions)
.setCategories(categories)
.setSuggestionMode(suggestionMode)
.setCombineSuggestionAndCondition(mCombineSuggestionAndCondition)
.setSuggestionConditionMode(suggestionConditionMode)
.build();
}
public List<Tile> getSuggestions() {
return mDashboardData.getSuggestions();
}
public void setCategoriesAndSuggestions(List<DashboardCategory> categories,
List<Tile> suggestions) {
if (mDashboardFeatureProvider.shouldTintIcon()) {
// TODO: Better place for tinting?
final TypedArray a = mContext.obtainStyledAttributes(new int[]{
android.R.attr.colorControlNormal});
final int tintColor = a.getColor(0, mContext.getColor(R.color.fallback_tintColor));
a.recycle();
for (int i = 0; i < categories.size(); i++) {
for (int j = 0; j < categories.get(i).tiles.size(); j++) {
final Tile tile = categories.get(i).tiles.get(j);
if (tile.isIconTintable) {
// If this drawable is tintable, tint it to match the color.
tile.icon.setTint(tintColor);
}
}
}
for (Tile suggestion : suggestions) {
if (suggestion.isIconTintable) {
suggestion.icon.setTint(tintColor);
}
}
}
final DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData)
.setSuggestions(suggestions)
.setCategories(categories)
.build();
notifyDashboardDataChanged(prevData);
List<Tile> shownSuggestions = null;
if (mCombineSuggestionAndCondition) {
final int mode = mDashboardData.getSuggestionConditionMode();
if (mode == DashboardData.HEADER_MODE_DEFAULT) {
shownSuggestions = suggestions.subList(0,
Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
} else if (mode != DashboardData.HEADER_MODE_COLLAPSED) {
shownSuggestions = suggestions;
}
} else {
switch (mDashboardData.getSuggestionMode()) {
case DashboardData.SUGGESTION_MODE_DEFAULT:
shownSuggestions = suggestions.subList(0,
Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
break;
case DashboardData.SUGGESTION_MODE_EXPANDED:
shownSuggestions = suggestions;
break;
}
}
if (shownSuggestions != null) {
for (Tile suggestion : shownSuggestions) {
final String identifier = mSuggestionFeatureProvider.getSuggestionIdentifier(
mContext, suggestion);
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, identifier);
mSuggestionsShownLogged.add(identifier);
}
}
}
public void setCategory(List<DashboardCategory> category) {
final DashboardData prevData = mDashboardData;
Log.d(TAG, "adapter setCategory called");
mDashboardData = new DashboardData.Builder(prevData)
.setCategories(category)
.build();
notifyDashboardDataChanged(prevData);
}
public void setConditions(List<Condition> conditions) {
final DashboardData prevData = mDashboardData;
Log.d(TAG, "adapter setConditions called");
if (mCombineSuggestionAndCondition) {
mDashboardData = new DashboardData.Builder(prevData)
.setConditions(conditions)
.build();
} else {
mDashboardData = new DashboardData.Builder(prevData)
.setConditions(conditions)
.setExpandedCondition(null)
.build();
}
notifyDashboardDataChanged(prevData);
}
public void onSuggestionDismissed() {
final List<Tile> suggestions = mDashboardData.getSuggestions();
if (suggestions != null && suggestions.size() == 1) {
// The only suggestion is dismissed, and the the empty suggestion container will
// remain as the dashboard item. Need to refresh the dashboard list.
final DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData)
.setSuggestions(null)
.build();
notifyDashboardDataChanged(prevData);
}
}
@Override
public void notifySummaryChanged(Tile tile) {
final int position = mDashboardData.getPositionByTile(tile);
if (position != DashboardData.POSITION_NOT_FOUND) {
// Since usually tile in parameter and tile in mCategories are same instance,
// which is hard to be detected by DiffUtil, so we notifyItemChanged directly.
notifyItemChanged(position, mDashboardData.getItemTypeByPosition(position));
}
}
@Override
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
if (viewType == R.layout.suggestion_condition_header) {
return new SuggestionAndConditionHeaderHolder(view);
}
if (viewType == R.layout.suggestion_condition_container) {
return new SuggestionAndConditionContainerHolder(view);
}
return new DashboardItemHolder(view);
}
@Override
public void onBindViewHolder(DashboardItemHolder holder, int position) {
final int type = mDashboardData.getItemTypeByPosition(position);
switch (type) {
case R.layout.dashboard_header_spacer:
onBindHeaderSpacer(holder, position);
break;
case R.layout.dashboard_tile:
final Tile tile = (Tile) mDashboardData.getItemEntityByPosition(position);
onBindTile(holder, tile);
holder.itemView.setTag(tile);
holder.itemView.setOnClickListener(mTileClickListener);
break;
case R.layout.suggestion_header:
onBindSuggestionHeader(holder, (DashboardData.SuggestionHeaderData)
mDashboardData.getItemEntityByPosition(position));
break;
case R.layout.suggestion_tile:
case R.layout.suggestion_tile_card:
final Tile suggestion = (Tile) mDashboardData.getItemEntityByPosition(position);
final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
mContext, suggestion);
// This is for cases when a suggestion is dismissed and the next one comes to view
if (!mSuggestionsShownLogged.contains(suggestionId)) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, suggestionId);
mSuggestionsShownLogged.add(suggestionId);
}
onBindTile(holder, suggestion);
View clickHandler = holder.itemView;
// If a view with @android:id/primary is defined, use that as the click handler
// instead.
final View primaryAction = holder.itemView.findViewById(android.R.id.primary);
if (primaryAction != null) {
clickHandler = primaryAction;
// set the item view to disabled to remove any touch effects
holder.itemView.setEnabled(false);
}
clickHandler.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_SUGGESTION, suggestionId);
((SettingsActivity) mContext).startSuggestion(suggestion.intent);
});
break;
case R.layout.condition_card:
final boolean isExpanded = mDashboardData.getItemEntityByPosition(position)
== mDashboardData.getExpandedCondition();
ConditionAdapterUtils.bindViews(
(Condition) mDashboardData.getItemEntityByPosition(position),
holder, isExpanded, mConditionClickListener, v -> onExpandClick(v));
break;
case R.layout.suggestion_condition_container:
onBindConditionAndSuggestion(
(SuggestionAndConditionContainerHolder) holder, position);
break;
case R.layout.suggestion_condition_header:
/* There are 2 different headers for the suggestions/conditions section. To minimize
visual animation when expanding and collapsing the suggestions/conditions, we are
using the same layout to represent the 2 headers:
1. Suggestion header - when there is any suggestion shown, the suggestion header
will be the first item on the section. It only has the text "Suggestion", and
do nothing when clicked. This header will not be shown when the section is
collapsed, in which case, the SuggestionCondition header will be
shown instead to show the summary info.
2. SuggestionCondition header - the header that shows the summary info for the
suggestion/condition that is currently hidden. It has the expand button to
expand the section. */
if (mDashboardData.getDisplayableSuggestionCount() > 0 && position == 1
&& mDashboardData.getSuggestionConditionMode()
!= DashboardData.HEADER_MODE_COLLAPSED) {
onBindSuggestionHeader((SuggestionAndConditionHeaderHolder) holder);
} else {
onBindSuggestionConditionHeader((SuggestionAndConditionHeaderHolder) holder,
(SuggestionConditionHeaderData)
mDashboardData.getItemEntityByPosition(position));
}
break;
case R.layout.suggestion_condition_footer:
holder.itemView.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, false);
DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData).setSuggestionConditionMode(
DashboardData.HEADER_MODE_COLLAPSED).build();
notifyDashboardDataChanged(prevData);
mRecyclerView.scrollToPosition(1);
});
break;
}
}
@Override
public long getItemId(int position) {
return mDashboardData.getItemIdByPosition(position);
}
@Override
public int getItemViewType(int position) {
return mDashboardData.getItemTypeByPosition(position);
}
@Override
public int getItemCount() {
return mDashboardData.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
// save the view so that we can scroll it when expanding/collapsing the suggestion and
// conditions.
mRecyclerView = recyclerView;
}
public void onPause() {
if (mDashboardData.getSuggestions() == null) {
return;
}
for (Tile suggestion : mDashboardData.getSuggestions()) {
String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
mContext, suggestion);
if (mSuggestionsShownLogged.contains(suggestionId)) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, suggestionId);
}
}
mSuggestionsShownLogged.clear();
}
// condition card is always expanded in new suggestion/condition UI.
// TODO: Remove when completely move to new suggestion/condition UI
@Deprecated
public void onExpandClick(View v) {
Condition expandedCondition = mDashboardData.getExpandedCondition();
if (v.getTag() == expandedCondition) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_COLLAPSE,
expandedCondition.getMetricsConstant());
expandedCondition = null;
} else {
expandedCondition = (Condition) v.getTag();
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND,
expandedCondition.getMetricsConstant());
}
updateExpandedCondition(expandedCondition);
}
public Object getItem(long itemId) {
return mDashboardData.getItemEntityById(itemId);
}
public Tile getSuggestion(int position) {
if (mCombineSuggestionAndCondition) {
return mSuggestionAdapter.getSuggestion(position);
}
return (Tile) getItem(getItemId(position));
}
@VisibleForTesting
void notifyDashboardDataChanged(DashboardData prevData) {
if (mFirstFrameDrawn && prevData != null) {
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DashboardData
.ItemsDataDiffCallback(prevData.getItemList(), mDashboardData.getItemList()));
diffResult.dispatchUpdatesTo(this);
} else {
mFirstFrameDrawn = true;
notifyDataSetChanged();
}
}
private void updateExpandedCondition(Condition condition) {
final DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData)
.setExpandedCondition(condition)
.build();
notifyDashboardDataChanged(prevData);
}
private void onBindHeaderSpacer(DashboardItemHolder holder, int position) {
if (mDashboardData.size() > (position + 1)) {
// The spacer that goes underneath the search bar needs to match the
// background of the first real view. That view is either a condition,
// a suggestion, or the dashboard item.
//
// If it's a dashboard item, set null background so it uses the parent's
// background like the other views. Otherwise, match the colors.
int nextType = mDashboardData.getItemTypeByPosition(position + 1);
int colorAttr = nextType == R.layout.suggestion_header
? android.R.attr.colorSecondary
: nextType == R.layout.condition_card
? android.R.attr.colorAccent
: DONT_SET_BACKGROUND_ATTR;
if (colorAttr != DONT_SET_BACKGROUND_ATTR) {
TypedArray array = holder.itemView.getContext()
.obtainStyledAttributes(new int[]{colorAttr});
@ColorInt int color = array.getColor(0, 0);
array.recycle();
holder.itemView.setBackgroundColor(color);
} else {
holder.itemView.setBackground(null);
}
}
}
@VisibleForTesting
void onBindSuggestionHeader(final DashboardItemHolder holder, DashboardData
.SuggestionHeaderData data) {
final boolean moreSuggestions = data.hasMoreSuggestions;
final int undisplayedSuggestionCount = data.undisplayedSuggestionCount;
holder.icon.setImageResource(moreSuggestions ? R.drawable.ic_expand_more
: R.drawable.ic_expand_less);
holder.title.setText(mContext.getString(R.string.suggestions_title, data.suggestionSize));
String summaryContentDescription;
if (moreSuggestions) {
summaryContentDescription = mContext.getResources().getQuantityString(
R.plurals.settings_suggestion_header_summary_hidden_items,
undisplayedSuggestionCount, undisplayedSuggestionCount);
} else {
summaryContentDescription = mContext.getString(R.string.condition_expand_hide);
}
holder.summary.setContentDescription(summaryContentDescription);
if (undisplayedSuggestionCount == 0) {
holder.summary.setText(null);
} else {
holder.summary.setText(
mContext.getString(R.string.suggestions_summary, undisplayedSuggestionCount));
}
holder.itemView.setOnClickListener(v -> {
final int suggestionMode;
if (moreSuggestions) {
suggestionMode = DashboardData.SUGGESTION_MODE_EXPANDED;
logSuggestions();
} else {
suggestionMode = DashboardData.SUGGESTION_MODE_COLLAPSED;
}
DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData)
.setSuggestionMode(suggestionMode)
.build();
notifyDashboardDataChanged(prevData);
});
}
private void logSuggestions() {
for (Tile suggestion : mDashboardData.getSuggestions()) {
final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
mContext, suggestion);
if (!mSuggestionsShownLogged.contains(suggestionId)) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
suggestionId);
mSuggestionsShownLogged.add(suggestionId);
}
}
}
private void onBindSuggestionHeader(final SuggestionAndConditionHeaderHolder holder) {
holder.title.setText(R.string.suggestions_title);
holder.title.setTextColor(Color.BLACK);
holder.icon.setVisibility(View.INVISIBLE);
holder.icons.removeAllViews();
holder.icons.setVisibility(View.INVISIBLE);
holder.summary.setVisibility(View.INVISIBLE);
holder.expandIndicator.setVisibility(View.INVISIBLE);
holder.itemView.setOnClickListener(null);
}
private void onBindSuggestionConditionHeader(final SuggestionAndConditionHeaderHolder holder,
SuggestionConditionHeaderData data) {
final int curMode = mDashboardData.getSuggestionConditionMode();
final int nextMode = data.hiddenSuggestionCount > 0 && data.conditionCount > 0
&& curMode != DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
? DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
: DashboardData.HEADER_MODE_FULLY_EXPANDED;
final boolean moreSuggestions = data.hiddenSuggestionCount > 0;
final boolean hasConditions = data.conditionCount > 0;
if (data.conditionCount > 0) {
holder.icon.setImageIcon(data.conditionIcons.get(0));
holder.icon.setVisibility(View.VISIBLE);
if (data.conditionCount == 1) {
holder.title.setText(data.title);
holder.title.setTextColor(Utils.getColorAccent(mContext));
holder.icons.setVisibility(View.INVISIBLE);
} else {
holder.title.setText(null);
updateConditionIcons(data.conditionIcons, holder.icons);
holder.icons.setVisibility(View.VISIBLE);
}
} else {
holder.icon.setVisibility(View.INVISIBLE);
holder.icons.setVisibility(View.INVISIBLE);
}
if (data.hiddenSuggestionCount > 0) {
holder.summary.setTextColor(Color.BLACK);
if (curMode == DashboardData.HEADER_MODE_COLLAPSED) {
if (data.conditionCount > 0) {
holder.summary.setText(mContext.getResources().getQuantityString(
R.plurals.suggestions_collapsed_summary,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
} else {
holder.title.setText(mContext.getResources().getQuantityString(
R.plurals.suggestions_collapsed_title,
data.hiddenSuggestionCount, data.hiddenSuggestionCount));
holder.title.setTextColor(Color.BLACK);
holder.summary.setText(null);
}
} else if (curMode == DashboardData.HEADER_MODE_DEFAULT) {
if (data.conditionCount > 0) {
holder.summary.setText(mContext.getString(
R.string.suggestions_summary, data.hiddenSuggestionCount));
} else {
holder.title.setText(mContext.getString(
R.string.suggestions_more_title, data.hiddenSuggestionCount));
holder.title.setTextColor(Color.BLACK);
holder.summary.setText(null);
}
}
} else if (data.conditionCount > 1) {
holder.summary.setTextColor(Utils.getColorAccent(mContext));
holder.summary.setText(
mContext.getString(R.string.condition_summary, data.conditionCount));
} else {
holder.summary.setText(null);
}
holder.summary.setVisibility(View.VISIBLE);
holder.expandIndicator.setVisibility(View.VISIBLE);
holder.itemView.setOnClickListener(v -> {
if (moreSuggestions ) {
logSuggestions();
} else if (hasConditions) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, true);
}
DashboardData prevData = mDashboardData;
final boolean wasCollapsed = curMode == DashboardData.HEADER_MODE_COLLAPSED;
mDashboardData = new DashboardData.Builder(prevData)
.setSuggestionConditionMode(nextMode).build();
notifyDashboardDataChanged(prevData);
if (wasCollapsed) {
mRecyclerView.scrollToPosition(1);
}
});
}
private void onBindConditionAndSuggestion(final SuggestionAndConditionContainerHolder holder,
int position) {
RecyclerView.Adapter<DashboardItemHolder> adapter;
// If there is suggestions to show, it will be at position 2 (position 0 = header spacer,
// position 1 is suggestion header.
if (position == 2 && mDashboardData.getSuggestions() != null) {
mSuggestionAdapter = new SuggestionAdapter(mContext, (List<Tile>)
mDashboardData.getItemEntityByPosition(position), mSuggestionsShownLogged);
adapter = mSuggestionAdapter;
mSuggestionDismissHandler = new SuggestionDismissController(mContext,
holder.data, mSuggestionParser, mCallback);
} else {
ConditionAdapterUtils.addDismiss(holder.data);
adapter = new ConditionAdapter(mContext,
(List<Condition>) mDashboardData.getItemEntityByPosition(position),
mDashboardData.getSuggestionConditionMode());
}
holder.data.setLayoutManager(new LinearLayoutManager(mContext));
holder.data.setAdapter(adapter);
}
private void onBindTile(DashboardItemHolder holder, Tile tile) {
if (tile.remoteViews != null) {
final ViewGroup itemView = (ViewGroup) holder.itemView;
itemView.removeAllViews();
itemView.addView(tile.remoteViews.apply(itemView.getContext(), itemView));
} else {
holder.icon.setImageDrawable(mCache.getIcon(tile.icon));
holder.title.setText(tile.title);
if (!TextUtils.isEmpty(tile.summary)) {
holder.summary.setText(tile.summary);
holder.summary.setVisibility(View.VISIBLE);
} else {
holder.summary.setVisibility(View.GONE);
}
}
}
private void onBindCategory(DashboardItemHolder holder, DashboardCategory category) {
holder.title.setText(category.title);
}
void onSaveInstanceState(Bundle outState) {
final List<Tile> suggestions = mDashboardData.getSuggestions();
final List<DashboardCategory> categories = mDashboardData.getCategories();
if (suggestions != null) {
outState.putParcelableArrayList(STATE_SUGGESTION_LIST, new ArrayList<>(suggestions));
}
if (categories != null) {
outState.putParcelableArrayList(STATE_CATEGORY_LIST, new ArrayList<>(categories));
}
outState.putInt(STATE_SUGGESTION_MODE, mDashboardData.getSuggestionMode());
outState.putStringArrayList(STATE_SUGGESTIONS_SHOWN_LOGGED, mSuggestionsShownLogged);
outState.putInt(STATE_SUGGESTION_CONDITION_MODE,
mDashboardData.getSuggestionConditionMode());
}
private void updateConditionIcons(List<Icon> icons, ViewGroup parent) {
if (icons == null || icons.size() < 2) {
parent.setVisibility(View.INVISIBLE);
return;
}
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
parent.removeAllViews();
for (int i = 1, size = icons.size(); i < size; i++) {
ImageView icon = (ImageView) inflater.inflate(
R.layout.condition_header_icon, parent, false);
icon.setImageIcon(icons.get(i));
parent.addView(icon);
}
parent.setVisibility(View.VISIBLE);
}
public static class IconCache {
private final Context mContext;
private final ArrayMap<Icon, Drawable> mMap = new ArrayMap<>();
public IconCache(Context context) {
mContext = context;
}
public Drawable getIcon(Icon icon) {
Drawable drawable = mMap.get(icon);
if (drawable == null) {
drawable = icon.loadDrawable(mContext);
mMap.put(icon, drawable);
}
return drawable;
}
}
public static class DashboardItemHolder extends RecyclerView.ViewHolder {
public final ImageView icon;
public final TextView title;
public final TextView summary;
public DashboardItemHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(android.R.id.icon);
title = itemView.findViewById(android.R.id.title);
summary = itemView.findViewById(android.R.id.summary);
}
}
public static class SuggestionAndConditionHeaderHolder extends DashboardItemHolder {
public final LinearLayout icons;
public final ImageView expandIndicator;
public SuggestionAndConditionHeaderHolder(View itemView) {
super(itemView);
icons = itemView.findViewById(id.additional_icons);
expandIndicator = itemView.findViewById(id.expand_indicator);
}
}
public static class SuggestionAndConditionContainerHolder extends DashboardItemHolder {
public final RecyclerView data;
public SuggestionAndConditionContainerHolder(View itemView) {
super(itemView);
data = itemView.findViewById(id.data);
}
}
}