Swipe to dismiss suggestions
- Move dismiss suggestion logic into feature provider - In DashboardData, use hashcode as suggestion's stable id. This is much more likely to provide a truely stable id for each suggestion card. Eventually I want to use hash for all tiles to provide stable id. - Add a SuggestionDismissionController to handle swipe to dismiss callbacks Change-Id: If3770f07a90c5469a0b86fc28f3eb5e4c17227cd Fix: 35159816 Test: make RunSettingsRoboTests
This commit is contained in:
@@ -55,11 +55,4 @@
|
|||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/overflow"
|
|
||||||
style="?android:attr/actionOverflowButtonStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="16dp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@@ -30,7 +30,6 @@ import android.content.pm.IPackageDataObserver;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ProviderInfo;
|
import android.content.pm.ProviderInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -39,7 +38,6 @@ import android.os.storage.StorageManager;
|
|||||||
import android.os.storage.VolumeInfo;
|
import android.os.storage.VolumeInfo;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceCategory;
|
import android.support.v7.preference.PreferenceCategory;
|
||||||
import android.text.format.Formatter;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.MutableInt;
|
import android.util.MutableInt;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -51,8 +49,6 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
|
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
|
||||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
|
||||||
import com.android.settingslib.applications.ApplicationsState.Callbacks;
|
import com.android.settingslib.applications.ApplicationsState.Callbacks;
|
||||||
import com.android.settingslib.applications.StorageStatsSource;
|
import com.android.settingslib.applications.StorageStatsSource;
|
||||||
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
|
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
|
||||||
|
@@ -17,21 +17,17 @@ package com.android.settings.dashboard;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
import android.support.v7.util.DiffUtil;
|
import android.support.v7.util.DiffUtil;
|
||||||
import android.support.v7.widget.PopupMenu;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextThemeWrapper;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -43,18 +39,17 @@ import com.android.settings.SettingsActivity;
|
|||||||
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
|
||||||
import com.android.settings.dashboard.conditional.Condition;
|
import com.android.settings.dashboard.conditional.Condition;
|
||||||
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
|
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
|
||||||
|
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.SuggestionParser;
|
import com.android.settingslib.SuggestionParser;
|
||||||
import com.android.settingslib.drawer.DashboardCategory;
|
import com.android.settingslib.drawer.DashboardCategory;
|
||||||
import com.android.settingslib.drawer.Tile;
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder>
|
public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder>
|
||||||
implements SummaryLoader.SummaryConsumer {
|
implements SummaryLoader.SummaryConsumer, SuggestionDismissController.Callback {
|
||||||
public static final String TAG = "DashboardAdapter";
|
public static final String TAG = "DashboardAdapter";
|
||||||
private static final String STATE_SUGGESTION_LIST = "suggestion_list";
|
private static final String STATE_SUGGESTION_LIST = "suggestion_list";
|
||||||
private static final String STATE_CATEGORY_LIST = "category_list";
|
private static final String STATE_CATEGORY_LIST = "category_list";
|
||||||
@@ -66,7 +61,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private final DashboardFeatureProvider mDashboardFeatureProvider;
|
private final DashboardFeatureProvider mDashboardFeatureProvider;
|
||||||
private final ArrayList<String> mSuggestionsShownLogged;
|
private final ArrayList<String> mSuggestionsShownLogged;
|
||||||
private SuggestionParser mSuggestionParser;
|
|
||||||
private boolean mFirstFrameDrawn;
|
private boolean mFirstFrameDrawn;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -115,7 +109,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
mDashboardFeatureProvider = FeatureFactory.getFactory(context)
|
mDashboardFeatureProvider = FeatureFactory.getFactory(context)
|
||||||
.getDashboardFeatureProvider(context);
|
.getDashboardFeatureProvider(context);
|
||||||
mCache = new IconCache(context);
|
mCache = new IconCache(context);
|
||||||
mSuggestionParser = parser;
|
|
||||||
|
|
||||||
setHasStableIds(true);
|
setHasStableIds(true);
|
||||||
|
|
||||||
@@ -218,22 +211,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this method to SuggestionParser or some other util class
|
|
||||||
public void disableSuggestion(Tile suggestion) {
|
|
||||||
if (mSuggestionParser == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boolean isSmartSuggestionEnabled = FeatureFactory.getFactory(mContext)
|
|
||||||
.getSuggestionFeatureProvider(mContext).isSmartSuggestionEnabled(mContext);
|
|
||||||
if (mSuggestionParser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
|
|
||||||
mContext.getPackageManager().setComponentEnabledSetting(
|
|
||||||
suggestion.intent.getComponent(),
|
|
||||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
|
||||||
PackageManager.DONT_KILL_APP);
|
|
||||||
mSuggestionParser.markCategoryDone(suggestion.category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
|
return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
|
||||||
@@ -277,13 +254,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
((SettingsActivity) mContext).startSuggestion(suggestion.intent);
|
((SettingsActivity) mContext).startSuggestion(suggestion.intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.itemView.findViewById(R.id.overflow).setOnClickListener(
|
|
||||||
new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
showRemoveOption(v, suggestion);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case R.layout.condition_card:
|
case R.layout.condition_card:
|
||||||
final boolean isExpanded = mDashboardData.getItemEntityByPosition(position)
|
final boolean isExpanded = mDashboardData.getItemEntityByPosition(position)
|
||||||
@@ -379,30 +349,24 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
notifyDashboardDataChanged(prevData);
|
notifyDashboardDataChanged(prevData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showRemoveOption(View v, final Tile suggestion) {
|
@Override
|
||||||
final PopupMenu popup = new PopupMenu(
|
public Tile getSuggestionForPosition(int position) {
|
||||||
new ContextThemeWrapper(mContext, R.style.Theme_AppCompat_DayNight), v);
|
return (Tile) mDashboardData.getItemEntityByPosition(position);
|
||||||
popup.getMenu().add(R.string.suggestion_remove).setOnMenuItemClickListener(
|
}
|
||||||
new MenuItem.OnMenuItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
mMetricsFeatureProvider.action(
|
|
||||||
mContext, MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION,
|
|
||||||
DashboardAdapter.getSuggestionIdentifier(mContext, suggestion));
|
|
||||||
disableSuggestion(suggestion);
|
|
||||||
List<Tile> suggestions = mDashboardData.getSuggestions();
|
|
||||||
suggestions.remove(suggestion);
|
|
||||||
|
|
||||||
DashboardData prevData = mDashboardData;
|
@Override
|
||||||
mDashboardData = new DashboardData.Builder(prevData)
|
public void onSuggestionDismissed(Tile suggestion) {
|
||||||
.setSuggestions(suggestions)
|
final List<Tile> suggestions = mDashboardData.getSuggestions();
|
||||||
.build();
|
if (suggestions == null) {
|
||||||
notifyDashboardDataChanged(prevData);
|
return;
|
||||||
|
}
|
||||||
|
suggestions.remove(suggestion);
|
||||||
|
|
||||||
return true;
|
final DashboardData prevData = mDashboardData;
|
||||||
}
|
mDashboardData = new DashboardData.Builder(prevData)
|
||||||
});
|
.setSuggestions(suggestions)
|
||||||
popup.show();
|
.build();
|
||||||
|
notifyDashboardDataChanged(prevData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -513,9 +477,9 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
|
|
||||||
public DashboardItemHolder(View itemView) {
|
public DashboardItemHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
icon = (ImageView) itemView.findViewById(android.R.id.icon);
|
icon = itemView.findViewById(android.R.id.icon);
|
||||||
title = (TextView) itemView.findViewById(android.R.id.title);
|
title = itemView.findViewById(android.R.id.title);
|
||||||
summary = (TextView) itemView.findViewById(android.R.id.summary);
|
summary = itemView.findViewById(android.R.id.summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,15 +19,17 @@ import android.annotation.IntDef;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.util.DiffUtil;
|
import android.support.v7.util.DiffUtil;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.conditional.Condition;
|
import com.android.settings.dashboard.conditional.Condition;
|
||||||
import com.android.settingslib.drawer.DashboardCategory;
|
import com.android.settingslib.drawer.DashboardCategory;
|
||||||
import com.android.settingslib.drawer.Tile;
|
import com.android.settingslib.drawer.Tile;
|
||||||
import com.android.settings.R;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description about data list used in the DashboardAdapter. In the data list each item can be
|
* Description about data list used in the DashboardAdapter. In the data list each item can be
|
||||||
@@ -44,7 +46,6 @@ public class DashboardData {
|
|||||||
|
|
||||||
// id namespace for different type of items.
|
// id namespace for different type of items.
|
||||||
private static final int NS_SPACER = 0;
|
private static final int NS_SPACER = 0;
|
||||||
private static final int NS_SUGGESTION = 1000;
|
|
||||||
private static final int NS_ITEMS = 2000;
|
private static final int NS_ITEMS = 2000;
|
||||||
private static final int NS_CONDITION = 3000;
|
private static final int NS_CONDITION = 3000;
|
||||||
|
|
||||||
@@ -171,6 +172,7 @@ public class DashboardData {
|
|||||||
* {@link #DEFAULT_SUGGESTION_COUNT}.
|
* {@link #DEFAULT_SUGGESTION_COUNT}.
|
||||||
*
|
*
|
||||||
* When in expanded mode, display all the suggestions.
|
* When in expanded mode, display all the suggestions.
|
||||||
|
*
|
||||||
* @return the count of suggestions to display
|
* @return the count of suggestions to display
|
||||||
*/
|
*/
|
||||||
public int getDisplayableSuggestionCount() {
|
public int getDisplayableSuggestionCount() {
|
||||||
@@ -178,7 +180,7 @@ public class DashboardData {
|
|||||||
return mSuggestionMode == SUGGESTION_MODE_DEFAULT
|
return mSuggestionMode == SUGGESTION_MODE_DEFAULT
|
||||||
? Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize)
|
? Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize)
|
||||||
: mSuggestionMode == SUGGESTION_MODE_EXPANDED
|
: mSuggestionMode == SUGGESTION_MODE_EXPANDED
|
||||||
? suggestionSize : 0;
|
? suggestionSize : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasMoreSuggestions() {
|
public boolean hasMoreSuggestions() {
|
||||||
@@ -198,9 +200,9 @@ public class DashboardData {
|
|||||||
* id stored in {@link Item} is shifted by {@paramref nameSpace}. This is a
|
* id stored in {@link Item} is shifted by {@paramref nameSpace}. This is a
|
||||||
* simple way to keep the id stable.
|
* simple way to keep the id stable.
|
||||||
*
|
*
|
||||||
* @param object maybe {@link Condition}, {@link Tile}, {@link DashboardCategory} or null
|
* @param object maybe {@link Condition}, {@link Tile}, {@link DashboardCategory} or null
|
||||||
* @param type type of the item, and value is the layout id
|
* @param type type of the item, and value is the layout id
|
||||||
* @param add flag about whether to add item into list
|
* @param add flag about whether to add item into list
|
||||||
* @param nameSpace namespace based on the type
|
* @param nameSpace namespace based on the type
|
||||||
*/
|
*/
|
||||||
private void countItem(Object object, int type, boolean add, int nameSpace) {
|
private void countItem(Object object, int type, boolean add, int nameSpace) {
|
||||||
@@ -210,6 +212,17 @@ public class DashboardData {
|
|||||||
mId++;
|
mId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special count item method for just suggestions. Id is calculated using suggestion hash
|
||||||
|
* instead of the position of suggestion in list. This is a more stable id than countItem.
|
||||||
|
*/
|
||||||
|
private void countSuggestion(Tile tile, boolean add) {
|
||||||
|
if (add) {
|
||||||
|
mItems.add(new Item(tile, R.layout.suggestion_tile, Objects.hash(tile.title), false));
|
||||||
|
}
|
||||||
|
mId++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the mItems list using mConditions, mSuggestions, mCategories data
|
* Build the mItems list using mConditions, mSuggestions, mCategories data
|
||||||
* and mIsShowingAll, mSuggestionMode flag.
|
* and mIsShowingAll, mSuggestionMode flag.
|
||||||
@@ -232,8 +245,7 @@ public class DashboardData {
|
|||||||
if (mSuggestions != null) {
|
if (mSuggestions != null) {
|
||||||
int maxSuggestions = getDisplayableSuggestionCount();
|
int maxSuggestions = getDisplayableSuggestionCount();
|
||||||
for (int i = 0; i < mSuggestions.size(); i++) {
|
for (int i = 0; i < mSuggestions.size(); i++) {
|
||||||
countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions,
|
countSuggestion(mSuggestions.get(i), i < maxSuggestions);
|
||||||
NS_SUGGESTION);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resetCount();
|
resetCount();
|
||||||
@@ -277,7 +289,6 @@ public class DashboardData {
|
|||||||
private List<Condition> mConditions;
|
private List<Condition> mConditions;
|
||||||
private List<Tile> mSuggestions;
|
private List<Tile> mSuggestions;
|
||||||
|
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +370,7 @@ public class DashboardData {
|
|||||||
return "condition"; // return anything but null to mark the payload
|
return "condition"; // return anything but null to mark the payload
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -433,11 +444,11 @@ public class DashboardData {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_DASHBOARD_CATEGORY:
|
case TYPE_DASHBOARD_CATEGORY:
|
||||||
// Only check title for dashboard category
|
// Only check title for dashboard category
|
||||||
return TextUtils.equals(((DashboardCategory)entity).title,
|
return TextUtils.equals(((DashboardCategory) entity).title,
|
||||||
((DashboardCategory) targetItem.entity).title);
|
((DashboardCategory) targetItem.entity).title);
|
||||||
case TYPE_DASHBOARD_TILE:
|
case TYPE_DASHBOARD_TILE:
|
||||||
final Tile localTile = (Tile)entity;
|
final Tile localTile = (Tile) entity;
|
||||||
final Tile targetTile = (Tile)targetItem.entity;
|
final Tile targetTile = (Tile) targetItem.entity;
|
||||||
|
|
||||||
// Only check title and summary for dashboard tile
|
// Only check title and summary for dashboard tile
|
||||||
return TextUtils.equals(localTile.title, targetTile.title)
|
return TextUtils.equals(localTile.title, targetTile.title)
|
||||||
|
@@ -35,6 +35,7 @@ import com.android.settings.dashboard.conditional.Condition;
|
|||||||
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
|
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
|
||||||
import com.android.settings.dashboard.conditional.ConditionManager;
|
import com.android.settings.dashboard.conditional.ConditionManager;
|
||||||
import com.android.settings.dashboard.conditional.FocusRecyclerView;
|
import com.android.settings.dashboard.conditional.FocusRecyclerView;
|
||||||
|
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
|
||||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.SuggestionParser;
|
import com.android.settingslib.SuggestionParser;
|
||||||
@@ -70,6 +71,7 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
private DashboardFeatureProvider mDashboardFeatureProvider;
|
private DashboardFeatureProvider mDashboardFeatureProvider;
|
||||||
private SuggestionFeatureProvider mSuggestionFeatureProvider;
|
private SuggestionFeatureProvider mSuggestionFeatureProvider;
|
||||||
private boolean isOnCategoriesChangedCalled;
|
private boolean isOnCategoriesChangedCalled;
|
||||||
|
private SuggestionDismissController mSuggestionDismissHandler;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -119,8 +121,7 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG_TIMING) {
|
if (DEBUG_TIMING) {
|
||||||
Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime)
|
Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||||
+ " ms");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +178,7 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle bundle) {
|
public void onViewCreated(View view, Bundle bundle) {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
|
mDashboard = view.findViewById(R.id.dashboard_container);
|
||||||
mLayoutManager = new LinearLayoutManager(getContext());
|
mLayoutManager = new LinearLayoutManager(getContext());
|
||||||
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
@@ -192,6 +193,8 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, mMetricsFeatureProvider,
|
mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, mMetricsFeatureProvider,
|
||||||
bundle, mConditionManager.getConditions());
|
bundle, mConditionManager.getConditions());
|
||||||
mDashboard.setAdapter(mAdapter);
|
mDashboard.setAdapter(mAdapter);
|
||||||
|
mSuggestionDismissHandler = new SuggestionDismissController(
|
||||||
|
getContext(), mDashboard, mSuggestionParser, mAdapter);
|
||||||
mDashboard.setItemAnimator(new DashboardItemAnimator());
|
mDashboard.setItemAnimator(new DashboardItemAnimator());
|
||||||
mSummaryLoader.setSummaryConsumer(mAdapter);
|
mSummaryLoader.setSummaryConsumer(mAdapter);
|
||||||
ConditionAdapterUtils.addDismiss(mDashboard);
|
ConditionAdapterUtils.addDismiss(mDashboard);
|
||||||
@@ -243,7 +246,7 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
List<String> suggestionIds = new ArrayList<>(suggestions.size());
|
List<String> suggestionIds = new ArrayList<>(suggestions.size());
|
||||||
for (Tile suggestion : suggestions) {
|
for (Tile suggestion : suggestions) {
|
||||||
suggestionIds.add(
|
suggestionIds.add(
|
||||||
DashboardAdapter.getSuggestionIdentifier(context, suggestion));
|
DashboardAdapter.getSuggestionIdentifier(context, suggestion));
|
||||||
}
|
}
|
||||||
// TODO: create a Suggestion class to maintain the id and other info
|
// TODO: create a Suggestion class to maintain the id and other info
|
||||||
mSuggestionFeatureProvider.rankSuggestions(suggestions, suggestionIds);
|
mSuggestionFeatureProvider.rankSuggestions(suggestions, suggestionIds);
|
||||||
@@ -251,7 +254,8 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
for (int i = 0; i < suggestions.size(); i++) {
|
for (int i = 0; i < suggestions.size(); i++) {
|
||||||
Tile suggestion = suggestions.get(i);
|
Tile suggestion = suggestions.get(i);
|
||||||
if (mSuggestionsChecks.isSuggestionComplete(suggestion)) {
|
if (mSuggestionsChecks.isSuggestionComplete(suggestion)) {
|
||||||
mAdapter.disableSuggestion(suggestion);
|
mSuggestionFeatureProvider.dismissSuggestion(
|
||||||
|
context, mSuggestionParser, suggestion);
|
||||||
suggestions.remove(i--);
|
suggestions.remove(i--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +281,7 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
// API that takes a single category.
|
// API that takes a single category.
|
||||||
List<DashboardCategory> categories = new ArrayList<>();
|
List<DashboardCategory> categories = new ArrayList<>();
|
||||||
categories.add(mDashboardFeatureProvider.getTilesForCategory(
|
categories.add(mDashboardFeatureProvider.getTilesForCategory(
|
||||||
CategoryKey.CATEGORY_HOMEPAGE));
|
CategoryKey.CATEGORY_HOMEPAGE));
|
||||||
if (suggestions != null) {
|
if (suggestions != null) {
|
||||||
mAdapter.setCategoriesAndSuggestions(categories, suggestions);
|
mAdapter.setCategoriesAndSuggestions(categories, suggestions);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -15,16 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.dashboard.conditional;
|
package com.android.settings.dashboard.conditional;
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnLayoutChangeListener;
|
|
||||||
import android.view.ViewGroup.LayoutParams;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
@@ -126,12 +121,6 @@ public class ConditionAdapterUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setHeight(View detailGroup, int height) {
|
|
||||||
final LayoutParams params = detailGroup.getLayoutParams();
|
|
||||||
params.height = height;
|
|
||||||
detailGroup.setLayoutParams(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setViewVisibility(View containerView, int viewId, boolean visible) {
|
private static void setViewVisibility(View containerView, int viewId, boolean visible) {
|
||||||
View view = containerView.findViewById(viewId);
|
View view = containerView.findViewById(viewId);
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.suggestions;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settingslib.SuggestionParser;
|
||||||
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
|
public class SuggestionDismissController extends ItemTouchHelper.SimpleCallback {
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns suggestion tile data from the callback
|
||||||
|
*/
|
||||||
|
Tile getSuggestionForPosition(int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a suggestion is dismissed.
|
||||||
|
*/
|
||||||
|
void onSuggestionDismissed(Tile suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final SuggestionFeatureProvider mSuggestionFeatureProvider;
|
||||||
|
private final SuggestionParser mSuggestionParser;
|
||||||
|
private final Callback mCallback;
|
||||||
|
|
||||||
|
public SuggestionDismissController(Context context, RecyclerView recyclerView,
|
||||||
|
SuggestionParser parser, Callback callback) {
|
||||||
|
super(0, ItemTouchHelper.START | ItemTouchHelper.END);
|
||||||
|
mContext = context;
|
||||||
|
mSuggestionParser = parser;
|
||||||
|
mSuggestionFeatureProvider = FeatureFactory.getFactory(context)
|
||||||
|
.getSuggestionFeatureProvider(context);
|
||||||
|
mCallback = callback;
|
||||||
|
final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(this);
|
||||||
|
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||||
|
RecyclerView.ViewHolder target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
if (viewHolder.getItemViewType() == R.layout.suggestion_tile) {
|
||||||
|
// Only return swipe direction for suggestion tiles. All other types are not swipeable.
|
||||||
|
return super.getSwipeDirs(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||||
|
if (mCallback == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Tile suggestion = mCallback.getSuggestionForPosition(viewHolder.getAdapterPosition());
|
||||||
|
mSuggestionFeatureProvider.dismissSuggestion(mContext, mSuggestionParser, suggestion);
|
||||||
|
mCallback.onSuggestionDismissed(suggestion);
|
||||||
|
}
|
||||||
|
}
|
@@ -18,6 +18,7 @@ package com.android.settings.dashboard.suggestions;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.android.settingslib.SuggestionParser;
|
||||||
import com.android.settingslib.drawer.Tile;
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -38,8 +39,14 @@ public interface SuggestionFeatureProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ranks the list of suggestions in place.
|
* Ranks the list of suggestions in place.
|
||||||
* @param suggestions: List of suggestion Tiles
|
*
|
||||||
* @param suggestionIds: List of suggestion ids corresponding to the suggestion tiles.
|
* @param suggestions List of suggestion Tiles
|
||||||
|
* @param suggestionIds List of suggestion ids corresponding to the suggestion tiles.
|
||||||
*/
|
*/
|
||||||
void rankSuggestions(final List<Tile> suggestions, List<String> suggestionIds);
|
void rankSuggestions(final List<Tile> suggestions, List<String> suggestionIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismisses a suggestion.
|
||||||
|
*/
|
||||||
|
void dismissSuggestion(Context context, SuggestionParser parser, Tile suggestion);
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,13 @@
|
|||||||
package com.android.settings.dashboard.suggestions;
|
package com.android.settings.dashboard.suggestions;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
|
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
import com.android.settings.dashboard.DashboardAdapter;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settingslib.SuggestionParser;
|
||||||
import com.android.settingslib.drawer.Tile;
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,6 +31,7 @@ import java.util.List;
|
|||||||
public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider {
|
public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider {
|
||||||
|
|
||||||
private final SuggestionRanker mSuggestionRanker;
|
private final SuggestionRanker mSuggestionRanker;
|
||||||
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSmartSuggestionEnabled(Context context) {
|
public boolean isSmartSuggestionEnabled(Context context) {
|
||||||
@@ -45,6 +52,8 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider
|
|||||||
public SuggestionFeatureProviderImpl(Context context) {
|
public SuggestionFeatureProviderImpl(Context context) {
|
||||||
mSuggestionRanker = new SuggestionRanker(
|
mSuggestionRanker = new SuggestionRanker(
|
||||||
new SuggestionFeaturizer(new EventStore(context.getApplicationContext())));
|
new SuggestionFeaturizer(new EventStore(context.getApplicationContext())));
|
||||||
|
mMetricsFeatureProvider = FeatureFactory.getFactory(context)
|
||||||
|
.getMetricsFeatureProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -52,4 +61,24 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider
|
|||||||
mSuggestionRanker.rankSuggestions(suggestions, suggestionIds);
|
mSuggestionRanker.rankSuggestions(suggestions, suggestionIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dismissSuggestion(Context context, SuggestionParser parser, Tile suggestion) {
|
||||||
|
if (parser == null || suggestion == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
context, MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION,
|
||||||
|
DashboardAdapter.getSuggestionIdentifier(context, suggestion));
|
||||||
|
|
||||||
|
final boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context);
|
||||||
|
if (!parser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.getPackageManager().setComponentEnabledSetting(
|
||||||
|
suggestion.intent.getComponent(),
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||||
|
PackageManager.DONT_KILL_APP);
|
||||||
|
parser.markCategoryDone(suggestion.category);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.suggestions;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settingslib.SuggestionParser;
|
||||||
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SuggestionDismissControllerTest {
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private Context mContext;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
@Mock
|
||||||
|
private SuggestionParser mSuggestionParser;
|
||||||
|
@Mock
|
||||||
|
private SuggestionDismissController.Callback mCallback;
|
||||||
|
|
||||||
|
private FakeFeatureFactory mFactory;
|
||||||
|
private SuggestionDismissController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
|
mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||||
|
|
||||||
|
when(mRecyclerView.getResources().getDimension(anyInt())).thenReturn(50F);
|
||||||
|
|
||||||
|
mController = new SuggestionDismissController(mContext, mRecyclerView,
|
||||||
|
mSuggestionParser, mCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onMove_alwaysReturnTrue() {
|
||||||
|
assertThat(mController.onMove(null, null, null)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSwipeDirs_isSuggestionTile_shouldReturnDirection() {
|
||||||
|
final RecyclerView.ViewHolder vh = mock(RecyclerView.ViewHolder.class);
|
||||||
|
when(vh.getItemViewType()).thenReturn(R.layout.suggestion_tile);
|
||||||
|
|
||||||
|
assertThat(mController.getSwipeDirs(mRecyclerView, vh))
|
||||||
|
.isEqualTo(ItemTouchHelper.START | ItemTouchHelper.END);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSwipeDirs_isNotSuggestionTile_shouldReturn0() {
|
||||||
|
final RecyclerView.ViewHolder vh = mock(RecyclerView.ViewHolder.class);
|
||||||
|
when(vh.getItemViewType()).thenReturn(R.layout.condition_card);
|
||||||
|
|
||||||
|
assertThat(mController.getSwipeDirs(mRecyclerView, vh))
|
||||||
|
.isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onSwiped_shouldTriggerDismissSuggestion() {
|
||||||
|
final RecyclerView.ViewHolder vh = mock(RecyclerView.ViewHolder.class);
|
||||||
|
|
||||||
|
mController.onSwiped(vh, ItemTouchHelper.START);
|
||||||
|
|
||||||
|
verify(mFactory.suggestionsFeatureProvider).dismissSuggestion(
|
||||||
|
eq(mContext), eq(mSuggestionParser), any(Tile.class));
|
||||||
|
verify(mCallback).onSuggestionDismissed(any(Tile.class));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.suggestions;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settingslib.SuggestionParser;
|
||||||
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SuggestionFeatureProviderImplTest {
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private SuggestionParser mSuggestionParser;
|
||||||
|
@Mock
|
||||||
|
private Tile mSuggestion;
|
||||||
|
|
||||||
|
private FakeFeatureFactory mFactory;
|
||||||
|
private SuggestionFeatureProviderImpl mProvider;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
|
mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||||
|
when(mContext.getApplicationContext()).thenReturn(RuntimeEnvironment.application);
|
||||||
|
mSuggestion.intent = new Intent().setClassName("pkg", "cls");
|
||||||
|
mSuggestion.category = "category";
|
||||||
|
|
||||||
|
mProvider = new SuggestionFeatureProviderImpl(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dismissSuggestion_noParserOrSuggestion_noop() {
|
||||||
|
mProvider.dismissSuggestion(mContext, null, null);
|
||||||
|
mProvider.dismissSuggestion(mContext, mSuggestionParser, null);
|
||||||
|
mProvider.dismissSuggestion(mContext, null, mSuggestion);
|
||||||
|
|
||||||
|
verifyZeroInteractions(mFactory.metricsFeatureProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dismissSuggestion_hasMoreDismissCount_shouldNotDisableComponent() {
|
||||||
|
when(mSuggestionParser.dismissSuggestion(any(Tile.class), anyBoolean()))
|
||||||
|
.thenReturn(false);
|
||||||
|
mProvider.dismissSuggestion(mContext, mSuggestionParser, mSuggestion);
|
||||||
|
|
||||||
|
verify(mFactory.metricsFeatureProvider).action(
|
||||||
|
eq(mContext),
|
||||||
|
eq(MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION),
|
||||||
|
anyString());
|
||||||
|
verify(mContext, never()).getPackageManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dismissSuggestion_hasNoMoreDismissCount_shouldDisableComponent() {
|
||||||
|
when(mSuggestionParser.dismissSuggestion(any(Tile.class), anyBoolean()))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
|
mProvider.dismissSuggestion(mContext, mSuggestionParser, mSuggestion);
|
||||||
|
|
||||||
|
verify(mFactory.metricsFeatureProvider).action(
|
||||||
|
eq(mContext),
|
||||||
|
eq(MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION),
|
||||||
|
anyString());
|
||||||
|
|
||||||
|
verify(mContext.getPackageManager())
|
||||||
|
.setComponentEnabledSetting(mSuggestion.intent.getComponent(),
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||||
|
PackageManager.DONT_KILL_APP);
|
||||||
|
verify(mSuggestionParser).markCategoryDone(mSuggestion.category);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user