Loading src/com/android/settings/dashboard/DashboardAdapter.java +42 −62 Original line number Diff line number Diff line Loading @@ -40,8 +40,8 @@ import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapterUtils; import com.android.settings.dashboard.suggestions.SuggestionDismissController; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.SuggestionParser; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; Loading @@ -60,6 +60,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash private final Context mContext; private final MetricsFeatureProvider mMetricsFeatureProvider; private final DashboardFeatureProvider mDashboardFeatureProvider; private final SuggestionFeatureProvider mSuggestionFeatureProvider; private final ArrayList<String> mSuggestionsShownLogged; private boolean mFirstFrameDrawn; Loading Loading @@ -97,17 +98,17 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash } }; public DashboardAdapter(Context context, SuggestionParser parser, MetricsFeatureProvider metricsFeatureProvider, Bundle savedInstanceState, public DashboardAdapter(Context context, Bundle savedInstanceState, List<Condition> conditions) { List<Tile> suggestions = null; List<DashboardCategory> categories = null; int suggestionMode = DashboardData.SUGGESTION_MODE_DEFAULT; mContext = context; mMetricsFeatureProvider = metricsFeatureProvider; mDashboardFeatureProvider = FeatureFactory.getFactory(context) .getDashboardFeatureProvider(context); final FeatureFactory factory = FeatureFactory.getFactory(context); mMetricsFeatureProvider = factory.getMetricsFeatureProvider(); mDashboardFeatureProvider = factory.getDashboardFeatureProvider(context); mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context); mCache = new IconCache(context); setHasStableIds(true); Loading @@ -120,7 +121,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash mSuggestionsShownLogged = savedInstanceState.getStringArrayList( STATE_SUGGESTIONS_SHOWN_LOGGED); } else { mSuggestionsShownLogged = new ArrayList<String>(); mSuggestionsShownLogged = new ArrayList<>(); } mDashboardData = new DashboardData.Builder() Loading Loading @@ -173,11 +174,11 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash } if (shownSuggestions != null) { for (Tile suggestion : shownSuggestions) { String suggestionId = getSuggestionIdentifier(mContext, suggestion); final String identifier = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, getSuggestionIdentifier(mContext, suggestion)); mSuggestionsShownLogged.add(getSuggestionIdentifier(mContext, suggestion)); mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, identifier); mSuggestionsShownLogged.add(identifier); } } } Loading Loading @@ -237,7 +238,8 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash break; case R.layout.suggestion_tile: final Tile suggestion = (Tile) mDashboardData.getItemEntityByPosition(position); String suggestionId = getSuggestionIdentifier(mContext, suggestion); 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( Loading @@ -245,14 +247,10 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash mSuggestionsShownLogged.add(suggestionId); } onBindTile(holder, suggestion); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.itemView.setOnClickListener(v -> { mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, DashboardAdapter.getSuggestionIdentifier(mContext, suggestion)); MetricsEvent.ACTION_SETTINGS_SUGGESTION, suggestionId); ((SettingsActivity) mContext).startSuggestion(suggestion.intent); } }); break; case R.layout.condition_card: Loading @@ -260,13 +258,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash == mDashboardData.getExpandedCondition(); ConditionAdapterUtils.bindViews( (Condition) mDashboardData.getItemEntityByPosition(position), holder, isExpanded, mConditionClickListener, new View.OnClickListener() { @Override public void onClick(View v) { onExpandClick(v); } }); holder, isExpanded, mConditionClickListener, v -> onExpandClick(v)); break; } } Loading @@ -291,7 +283,8 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash return; } for (Tile suggestion : mDashboardData.getSuggestions()) { String suggestionId = getSuggestionIdentifier(mContext, suggestion); String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); if (mSuggestionsShownLogged.contains(suggestionId)) { mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, suggestionId); Loading Loading @@ -320,16 +313,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash return mDashboardData.getItemEntityById(itemId); } public static String getSuggestionIdentifier(Context context, Tile suggestion) { String packageName = suggestion.intent.getComponent().getPackageName(); if (packageName.equals(context.getPackageName())) { // Since Settings provides several suggestions, fill in the class instead of the // package for these. packageName = suggestion.intent.getComponent().getClassName(); } return packageName; } private void notifyDashboardDataChanged(DashboardData prevData) { if (mFirstFrameDrawn && prevData != null) { final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DashboardData Loading Loading @@ -394,16 +377,14 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash holder.summary.setText( mContext.getString(R.string.suggestions_summary, undisplayedSuggestionCount)); } holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.itemView.setOnClickListener(v -> { final int suggestionMode; if (moreSuggestions) { suggestionMode = DashboardData.SUGGESTION_MODE_EXPANDED; for (Tile suggestion : mDashboardData.getSuggestions()) { String suggestionId = DashboardAdapter.getSuggestionIdentifier(mContext, suggestion); final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); if (!mSuggestionsShownLogged.contains(suggestionId)) { mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, Loading @@ -420,7 +401,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash .setSuggestionMode(suggestionMode) .build(); notifyDashboardDataChanged(prevData); } }); } Loading src/com/android/settings/dashboard/DashboardSummary.java +3 −4 Original line number Diff line number Diff line Loading @@ -190,8 +190,7 @@ public class DashboardSummary extends InstrumentedFragment mDashboard.addItemDecoration(new DashboardDecorator(getContext())); mDashboard.setListener(this); Log.d(TAG, "adapter created"); mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, mMetricsFeatureProvider, bundle, mConditionManager.getConditions()); mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions()); mDashboard.setAdapter(mAdapter); mSuggestionDismissHandler = new SuggestionDismissController( getContext(), mDashboard, mSuggestionParser, mAdapter); Loading Loading @@ -245,8 +244,8 @@ public class DashboardSummary extends InstrumentedFragment if (isSmartSuggestionEnabled) { List<String> suggestionIds = new ArrayList<>(suggestions.size()); for (Tile suggestion : suggestions) { suggestionIds.add( DashboardAdapter.getSuggestionIdentifier(context, suggestion)); suggestionIds.add(mSuggestionFeatureProvider.getSuggestionIdentifier( context, suggestion)); } // TODO: create a Suggestion class to maintain the id and other info mSuggestionFeatureProvider.rankSuggestions(suggestions, suggestionIds); Loading src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java +5 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,9 @@ public interface SuggestionFeatureProvider { * Dismisses a suggestion. */ void dismissSuggestion(Context context, SuggestionParser parser, Tile suggestion); /** * Returns an identifier for the suggestion */ String getSuggestionIdentifier(Context context, Tile suggestion); } src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +18 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ 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; Loading Loading @@ -50,9 +49,10 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider public SuggestionFeatureProviderImpl(Context context) { final Context appContext = context.getApplicationContext(); mSuggestionRanker = new SuggestionRanker( new SuggestionFeaturizer(new EventStore(context.getApplicationContext()))); mMetricsFeatureProvider = FeatureFactory.getFactory(context) new SuggestionFeaturizer(new EventStore(appContext))); mMetricsFeatureProvider = FeatureFactory.getFactory(appContext) .getMetricsFeatureProvider(); } Loading @@ -68,7 +68,7 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider } mMetricsFeatureProvider.action( context, MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION, DashboardAdapter.getSuggestionIdentifier(context, suggestion)); getSuggestionIdentifier(context, suggestion)); final boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context); if (!parser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) { Loading @@ -81,4 +81,18 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider parser.markCategoryDone(suggestion.category); } @Override public String getSuggestionIdentifier(Context context, Tile suggestion) { if (suggestion.intent == null || suggestion.intent.getComponent() == null) { return "unknown_suggestion"; } String packageName = suggestion.intent.getComponent().getPackageName(); if (packageName.equals(context.getPackageName())) { // Since Settings provides several suggestions, fill in the class instead of the // package for these. packageName = suggestion.intent.getComponent().getClassName(); } return packageName; } } tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +38 −42 Original line number Diff line number Diff line Loading @@ -21,35 +21,32 @@ import android.content.Intent; import android.content.res.Resources; import android.view.View; import android.widget.FrameLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settingslib.drawer.DashboardCategory; 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.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; import static com.google.common.truth.Truth.assertThat; import org.mockito.Matchers; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -64,20 +61,19 @@ import static org.mockito.Mockito.when; }) public class DashboardAdapterTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private View mView; @Mock private Condition mCondition; @Mock private MetricsFeatureProvider mMetricsFeatureProvider; @Mock private Resources mResources; @Mock private DashboardData mDashboardData; @Captor private ArgumentCaptor<Integer> mActionCategoryCaptor = ArgumentCaptor.forClass(Integer.class); @Captor private ArgumentCaptor<String> mActionPackageCaptor = ArgumentCaptor.forClass(String.class); private FakeFeatureFactory mFactory; private DashboardAdapter mDashboardAdapter; private DashboardAdapter.DashboardItemHolder mSuggestionHolder; private DashboardData.SuggestionHeaderData mSuggestionHeaderData; Loading @@ -85,15 +81,20 @@ public class DashboardAdapterTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = RuntimeEnvironment.application; context = spy(context); when(context.getResources()).thenReturn(mResources); when(mResources .getQuantityString(any(int.class), any(int.class), Matchers.<Object>anyVararg())) FakeFeatureFactory.setupForTest(mContext); mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); when(mFactory.suggestionsFeatureProvider .getSuggestionIdentifier(any(Context.class), any(Tile.class))) .thenAnswer(invocation -> { final Object[] args = invocation.getArguments(); return ((Tile)args[1]).intent.getComponent().getPackageName(); }); when(mContext.getResources()).thenReturn(mResources); when(mResources.getQuantityString(any(int.class), any(int.class), any())) .thenReturn(""); FakeFeatureFactory.setupForTest(context); mDashboardAdapter = new DashboardAdapter(context, null, mMetricsFeatureProvider, null, null); mDashboardAdapter = new DashboardAdapter(mContext, null, null); mSuggestionHeaderData = new DashboardData.SuggestionHeaderData(true, 1, 0); when(mView.getTag()).thenReturn(mCondition); } Loading @@ -109,7 +110,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_NotExpanded() { setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); verify(mMetricsFeatureProvider, times(2)).action( verify(mFactory.metricsFeatureProvider, times(2)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2"}; Loading @@ -117,15 +118,15 @@ public class DashboardAdapterTest { MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION }; assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); assertThat(mActionCategoryCaptor.getAllValues().toArray()).isEqualTo(expectedActions); assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); } @Test public void testSuggestionsLogs_NotExpandedAndPaused() { setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(4)).action( verify(mFactory.metricsFeatureProvider, times(4)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg1", "pkg2"}; Loading @@ -134,8 +135,8 @@ public class DashboardAdapterTest { MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION}; assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); assertThat(mActionCategoryCaptor.getAllValues().toArray()).isEqualTo(expectedActions); assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); } @Test Loading @@ -144,7 +145,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(3)).action( verify(mFactory.metricsFeatureProvider, times(3)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg3"}; Loading @@ -164,7 +165,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(6)).action( verify(mFactory.metricsFeatureProvider, times(6)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg3", "pkg1", "pkg2", "pkg3"}; Loading @@ -187,7 +188,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(7)).action( verify(mFactory.metricsFeatureProvider, times(7)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{ Loading @@ -213,7 +214,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(10)).action( verify(mFactory.metricsFeatureProvider, times(10)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{ Loading @@ -240,7 +241,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(1)).action( verify(mFactory.metricsFeatureProvider, times(1)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1"}; Loading @@ -258,7 +259,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(2)).action( verify(mFactory.metricsFeatureProvider, times(2)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1"}; Loading @@ -277,7 +278,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(3)).action( verify(mFactory.metricsFeatureProvider, times(3)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1", "pkg1"}; Loading @@ -298,7 +299,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(4)).action( verify(mFactory.metricsFeatureProvider, times(4)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1", "pkg1", "pkg1"}; Loading @@ -313,23 +314,18 @@ public class DashboardAdapterTest { } private List<Tile> makeSuggestions(String[] pkgNames) { List<Tile> suggestions = new ArrayList<Tile>(); final List<Tile> suggestions = new ArrayList<>(); for (String pkgName : pkgNames) { suggestions.add(makeSuggestion(pkgName, "cls")); } return suggestions; } private Tile makeSuggestion(String pkgName, String className) { Tile suggestion = new Tile(); suggestion.intent = new Intent("action"); suggestion.intent.setComponent(new ComponentName(pkgName, className)); return suggestion; suggestion.intent.setComponent(new ComponentName(pkgName, "cls")); suggestions.add(suggestion); } return suggestions; } private void setUpSuggestions(List<Tile> suggestions) { mDashboardAdapter.setCategoriesAndSuggestions( new ArrayList<DashboardCategory>(), suggestions); mDashboardAdapter.setCategoriesAndSuggestions(new ArrayList<>(), suggestions); mSuggestionHolder = mDashboardAdapter.onCreateViewHolder( new FrameLayout(RuntimeEnvironment.application), mDashboardAdapter.getItemViewType(0)); Loading Loading
src/com/android/settings/dashboard/DashboardAdapter.java +42 −62 Original line number Diff line number Diff line Loading @@ -40,8 +40,8 @@ import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapterUtils; import com.android.settings.dashboard.suggestions.SuggestionDismissController; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.SuggestionParser; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; Loading @@ -60,6 +60,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash private final Context mContext; private final MetricsFeatureProvider mMetricsFeatureProvider; private final DashboardFeatureProvider mDashboardFeatureProvider; private final SuggestionFeatureProvider mSuggestionFeatureProvider; private final ArrayList<String> mSuggestionsShownLogged; private boolean mFirstFrameDrawn; Loading Loading @@ -97,17 +98,17 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash } }; public DashboardAdapter(Context context, SuggestionParser parser, MetricsFeatureProvider metricsFeatureProvider, Bundle savedInstanceState, public DashboardAdapter(Context context, Bundle savedInstanceState, List<Condition> conditions) { List<Tile> suggestions = null; List<DashboardCategory> categories = null; int suggestionMode = DashboardData.SUGGESTION_MODE_DEFAULT; mContext = context; mMetricsFeatureProvider = metricsFeatureProvider; mDashboardFeatureProvider = FeatureFactory.getFactory(context) .getDashboardFeatureProvider(context); final FeatureFactory factory = FeatureFactory.getFactory(context); mMetricsFeatureProvider = factory.getMetricsFeatureProvider(); mDashboardFeatureProvider = factory.getDashboardFeatureProvider(context); mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context); mCache = new IconCache(context); setHasStableIds(true); Loading @@ -120,7 +121,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash mSuggestionsShownLogged = savedInstanceState.getStringArrayList( STATE_SUGGESTIONS_SHOWN_LOGGED); } else { mSuggestionsShownLogged = new ArrayList<String>(); mSuggestionsShownLogged = new ArrayList<>(); } mDashboardData = new DashboardData.Builder() Loading Loading @@ -173,11 +174,11 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash } if (shownSuggestions != null) { for (Tile suggestion : shownSuggestions) { String suggestionId = getSuggestionIdentifier(mContext, suggestion); final String identifier = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, getSuggestionIdentifier(mContext, suggestion)); mSuggestionsShownLogged.add(getSuggestionIdentifier(mContext, suggestion)); mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, identifier); mSuggestionsShownLogged.add(identifier); } } } Loading Loading @@ -237,7 +238,8 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash break; case R.layout.suggestion_tile: final Tile suggestion = (Tile) mDashboardData.getItemEntityByPosition(position); String suggestionId = getSuggestionIdentifier(mContext, suggestion); 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( Loading @@ -245,14 +247,10 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash mSuggestionsShownLogged.add(suggestionId); } onBindTile(holder, suggestion); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.itemView.setOnClickListener(v -> { mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, DashboardAdapter.getSuggestionIdentifier(mContext, suggestion)); MetricsEvent.ACTION_SETTINGS_SUGGESTION, suggestionId); ((SettingsActivity) mContext).startSuggestion(suggestion.intent); } }); break; case R.layout.condition_card: Loading @@ -260,13 +258,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash == mDashboardData.getExpandedCondition(); ConditionAdapterUtils.bindViews( (Condition) mDashboardData.getItemEntityByPosition(position), holder, isExpanded, mConditionClickListener, new View.OnClickListener() { @Override public void onClick(View v) { onExpandClick(v); } }); holder, isExpanded, mConditionClickListener, v -> onExpandClick(v)); break; } } Loading @@ -291,7 +283,8 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash return; } for (Tile suggestion : mDashboardData.getSuggestions()) { String suggestionId = getSuggestionIdentifier(mContext, suggestion); String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); if (mSuggestionsShownLogged.contains(suggestionId)) { mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, suggestionId); Loading Loading @@ -320,16 +313,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash return mDashboardData.getItemEntityById(itemId); } public static String getSuggestionIdentifier(Context context, Tile suggestion) { String packageName = suggestion.intent.getComponent().getPackageName(); if (packageName.equals(context.getPackageName())) { // Since Settings provides several suggestions, fill in the class instead of the // package for these. packageName = suggestion.intent.getComponent().getClassName(); } return packageName; } private void notifyDashboardDataChanged(DashboardData prevData) { if (mFirstFrameDrawn && prevData != null) { final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DashboardData Loading Loading @@ -394,16 +377,14 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash holder.summary.setText( mContext.getString(R.string.suggestions_summary, undisplayedSuggestionCount)); } holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.itemView.setOnClickListener(v -> { final int suggestionMode; if (moreSuggestions) { suggestionMode = DashboardData.SUGGESTION_MODE_EXPANDED; for (Tile suggestion : mDashboardData.getSuggestions()) { String suggestionId = DashboardAdapter.getSuggestionIdentifier(mContext, suggestion); final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier( mContext, suggestion); if (!mSuggestionsShownLogged.contains(suggestionId)) { mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, Loading @@ -420,7 +401,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash .setSuggestionMode(suggestionMode) .build(); notifyDashboardDataChanged(prevData); } }); } Loading
src/com/android/settings/dashboard/DashboardSummary.java +3 −4 Original line number Diff line number Diff line Loading @@ -190,8 +190,7 @@ public class DashboardSummary extends InstrumentedFragment mDashboard.addItemDecoration(new DashboardDecorator(getContext())); mDashboard.setListener(this); Log.d(TAG, "adapter created"); mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, mMetricsFeatureProvider, bundle, mConditionManager.getConditions()); mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions()); mDashboard.setAdapter(mAdapter); mSuggestionDismissHandler = new SuggestionDismissController( getContext(), mDashboard, mSuggestionParser, mAdapter); Loading Loading @@ -245,8 +244,8 @@ public class DashboardSummary extends InstrumentedFragment if (isSmartSuggestionEnabled) { List<String> suggestionIds = new ArrayList<>(suggestions.size()); for (Tile suggestion : suggestions) { suggestionIds.add( DashboardAdapter.getSuggestionIdentifier(context, suggestion)); suggestionIds.add(mSuggestionFeatureProvider.getSuggestionIdentifier( context, suggestion)); } // TODO: create a Suggestion class to maintain the id and other info mSuggestionFeatureProvider.rankSuggestions(suggestions, suggestionIds); Loading
src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java +5 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,9 @@ public interface SuggestionFeatureProvider { * Dismisses a suggestion. */ void dismissSuggestion(Context context, SuggestionParser parser, Tile suggestion); /** * Returns an identifier for the suggestion */ String getSuggestionIdentifier(Context context, Tile suggestion); }
src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +18 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ 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; Loading Loading @@ -50,9 +49,10 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider public SuggestionFeatureProviderImpl(Context context) { final Context appContext = context.getApplicationContext(); mSuggestionRanker = new SuggestionRanker( new SuggestionFeaturizer(new EventStore(context.getApplicationContext()))); mMetricsFeatureProvider = FeatureFactory.getFactory(context) new SuggestionFeaturizer(new EventStore(appContext))); mMetricsFeatureProvider = FeatureFactory.getFactory(appContext) .getMetricsFeatureProvider(); } Loading @@ -68,7 +68,7 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider } mMetricsFeatureProvider.action( context, MetricsProto.MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION, DashboardAdapter.getSuggestionIdentifier(context, suggestion)); getSuggestionIdentifier(context, suggestion)); final boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context); if (!parser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) { Loading @@ -81,4 +81,18 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider parser.markCategoryDone(suggestion.category); } @Override public String getSuggestionIdentifier(Context context, Tile suggestion) { if (suggestion.intent == null || suggestion.intent.getComponent() == null) { return "unknown_suggestion"; } String packageName = suggestion.intent.getComponent().getPackageName(); if (packageName.equals(context.getPackageName())) { // Since Settings provides several suggestions, fill in the class instead of the // package for these. packageName = suggestion.intent.getComponent().getClassName(); } return packageName; } }
tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +38 −42 Original line number Diff line number Diff line Loading @@ -21,35 +21,32 @@ import android.content.Intent; import android.content.res.Resources; import android.view.View; import android.widget.FrameLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settingslib.drawer.DashboardCategory; 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.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; import static com.google.common.truth.Truth.assertThat; import org.mockito.Matchers; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -64,20 +61,19 @@ import static org.mockito.Mockito.when; }) public class DashboardAdapterTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private View mView; @Mock private Condition mCondition; @Mock private MetricsFeatureProvider mMetricsFeatureProvider; @Mock private Resources mResources; @Mock private DashboardData mDashboardData; @Captor private ArgumentCaptor<Integer> mActionCategoryCaptor = ArgumentCaptor.forClass(Integer.class); @Captor private ArgumentCaptor<String> mActionPackageCaptor = ArgumentCaptor.forClass(String.class); private FakeFeatureFactory mFactory; private DashboardAdapter mDashboardAdapter; private DashboardAdapter.DashboardItemHolder mSuggestionHolder; private DashboardData.SuggestionHeaderData mSuggestionHeaderData; Loading @@ -85,15 +81,20 @@ public class DashboardAdapterTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = RuntimeEnvironment.application; context = spy(context); when(context.getResources()).thenReturn(mResources); when(mResources .getQuantityString(any(int.class), any(int.class), Matchers.<Object>anyVararg())) FakeFeatureFactory.setupForTest(mContext); mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); when(mFactory.suggestionsFeatureProvider .getSuggestionIdentifier(any(Context.class), any(Tile.class))) .thenAnswer(invocation -> { final Object[] args = invocation.getArguments(); return ((Tile)args[1]).intent.getComponent().getPackageName(); }); when(mContext.getResources()).thenReturn(mResources); when(mResources.getQuantityString(any(int.class), any(int.class), any())) .thenReturn(""); FakeFeatureFactory.setupForTest(context); mDashboardAdapter = new DashboardAdapter(context, null, mMetricsFeatureProvider, null, null); mDashboardAdapter = new DashboardAdapter(mContext, null, null); mSuggestionHeaderData = new DashboardData.SuggestionHeaderData(true, 1, 0); when(mView.getTag()).thenReturn(mCondition); } Loading @@ -109,7 +110,7 @@ public class DashboardAdapterTest { @Test public void testSuggestionsLogs_NotExpanded() { setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); verify(mMetricsFeatureProvider, times(2)).action( verify(mFactory.metricsFeatureProvider, times(2)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2"}; Loading @@ -117,15 +118,15 @@ public class DashboardAdapterTest { MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION }; assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); assertThat(mActionCategoryCaptor.getAllValues().toArray()).isEqualTo(expectedActions); assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); } @Test public void testSuggestionsLogs_NotExpandedAndPaused() { setUpSuggestions(makeSuggestions(new String[]{"pkg1", "pkg2", "pkg3"})); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(4)).action( verify(mFactory.metricsFeatureProvider, times(4)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg1", "pkg2"}; Loading @@ -134,8 +135,8 @@ public class DashboardAdapterTest { MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION}; assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); assertThat(mActionCategoryCaptor.getAllValues().toArray()).isEqualTo(expectedActions); assertThat(mActionPackageCaptor.getAllValues().toArray()).isEqualTo(expectedPackages); } @Test Loading @@ -144,7 +145,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(3)).action( verify(mFactory.metricsFeatureProvider, times(3)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg3"}; Loading @@ -164,7 +165,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(6)).action( verify(mFactory.metricsFeatureProvider, times(6)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg2", "pkg3", "pkg1", "pkg2", "pkg3"}; Loading @@ -187,7 +188,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(7)).action( verify(mFactory.metricsFeatureProvider, times(7)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{ Loading @@ -213,7 +214,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(10)).action( verify(mFactory.metricsFeatureProvider, times(10)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{ Loading @@ -240,7 +241,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(1)).action( verify(mFactory.metricsFeatureProvider, times(1)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1"}; Loading @@ -258,7 +259,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(2)).action( verify(mFactory.metricsFeatureProvider, times(2)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1"}; Loading @@ -277,7 +278,7 @@ public class DashboardAdapterTest { mDashboardAdapter.onBindSuggestionHeader( mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); verify(mMetricsFeatureProvider, times(3)).action( verify(mFactory.metricsFeatureProvider, times(3)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1", "pkg1"}; Loading @@ -298,7 +299,7 @@ public class DashboardAdapterTest { mSuggestionHolder, mSuggestionHeaderData); mSuggestionHolder.itemView.callOnClick(); mDashboardAdapter.onPause(); verify(mMetricsFeatureProvider, times(4)).action( verify(mFactory.metricsFeatureProvider, times(4)).action( any(Context.class), mActionCategoryCaptor.capture(), mActionPackageCaptor.capture()); String[] expectedPackages = new String[]{"pkg1", "pkg1", "pkg1", "pkg1"}; Loading @@ -313,23 +314,18 @@ public class DashboardAdapterTest { } private List<Tile> makeSuggestions(String[] pkgNames) { List<Tile> suggestions = new ArrayList<Tile>(); final List<Tile> suggestions = new ArrayList<>(); for (String pkgName : pkgNames) { suggestions.add(makeSuggestion(pkgName, "cls")); } return suggestions; } private Tile makeSuggestion(String pkgName, String className) { Tile suggestion = new Tile(); suggestion.intent = new Intent("action"); suggestion.intent.setComponent(new ComponentName(pkgName, className)); return suggestion; suggestion.intent.setComponent(new ComponentName(pkgName, "cls")); suggestions.add(suggestion); } return suggestions; } private void setUpSuggestions(List<Tile> suggestions) { mDashboardAdapter.setCategoriesAndSuggestions( new ArrayList<DashboardCategory>(), suggestions); mDashboardAdapter.setCategoriesAndSuggestions(new ArrayList<>(), suggestions); mSuggestionHolder = mDashboardAdapter.onCreateViewHolder( new FrameLayout(RuntimeEnvironment.application), mDashboardAdapter.getItemViewType(0)); Loading