Merge "Separate suggestions and conditions."
This commit is contained in:
committed by
Android (Google) Code Review
commit
2ce430afc4
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.service.settings.suggestions.Suggestion;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.dashboard.conditional.Condition;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionAdapterV2;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||
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.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH,
|
||||
sdk = TestConfig.SDK_VERSION,
|
||||
shadows = {
|
||||
SettingsShadowResources.class,
|
||||
SettingsShadowResources.SettingsShadowTheme.class,
|
||||
})
|
||||
public class DashboardAdapterV2Test {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private SettingsActivity mContext;
|
||||
@Mock
|
||||
private View mView;
|
||||
@Mock
|
||||
private Condition mCondition;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
private FakeFeatureFactory mFactory;
|
||||
private DashboardAdapterV2 mDashboardAdapter;
|
||||
private List<Condition> mConditionList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mFactory = FakeFeatureFactory.setupForTest();
|
||||
when(mFactory.dashboardFeatureProvider.shouldTintIcon()).thenReturn(true);
|
||||
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getQuantityString(any(int.class), any(int.class), any()))
|
||||
.thenReturn("");
|
||||
|
||||
mConditionList = new ArrayList<>();
|
||||
mConditionList.add(mCondition);
|
||||
when(mCondition.shouldShow()).thenReturn(true);
|
||||
mDashboardAdapter = new DashboardAdapterV2(mContext, null /* savedInstanceState */,
|
||||
mConditionList, null /* suggestionControllerMixin */, null /* lifecycle */);
|
||||
when(mView.getTag()).thenReturn(mCondition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestionDismissed_notOnlySuggestion_updateSuggestionOnly() {
|
||||
final DashboardAdapterV2 adapter =
|
||||
spy(new DashboardAdapterV2(mContext, null /* savedInstanceState */,
|
||||
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */));
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1", "pkg2", "pkg3");
|
||||
adapter.setSuggestions(suggestions);
|
||||
|
||||
final RecyclerView data = mock(RecyclerView.class);
|
||||
when(data.getResources()).thenReturn(mResources);
|
||||
when(data.getContext()).thenReturn(mContext);
|
||||
when(mResources.getDisplayMetrics()).thenReturn(mock(DisplayMetrics.class));
|
||||
final View itemView = mock(View.class);
|
||||
when(itemView.findViewById(R.id.suggestion_list)).thenReturn(data);
|
||||
when(itemView.findViewById(android.R.id.summary)).thenReturn(mock(TextView.class));
|
||||
final DashboardAdapterV2.SuggestionContainerHolder holder =
|
||||
new DashboardAdapterV2.SuggestionContainerHolder(itemView);
|
||||
|
||||
adapter.onBindSuggestion(holder, 0);
|
||||
|
||||
final DashboardDataV2 dashboardData = adapter.mDashboardData;
|
||||
reset(adapter); // clear interactions tracking
|
||||
|
||||
final Suggestion suggestionToRemove = suggestions.get(1);
|
||||
adapter.onSuggestionClosed(suggestionToRemove);
|
||||
|
||||
assertThat(adapter.mDashboardData).isEqualTo(dashboardData);
|
||||
assertThat(suggestions.size()).isEqualTo(2);
|
||||
assertThat(suggestions.contains(suggestionToRemove)).isFalse();
|
||||
verify(adapter, never()).notifyDashboardDataChanged(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestionDismissed_moreThanTwoSuggestions_shouldNotCrash() {
|
||||
final RecyclerView data = new RecyclerView(RuntimeEnvironment.application);
|
||||
final View itemView = mock(View.class);
|
||||
when(itemView.findViewById(R.id.suggestion_list)).thenReturn(data);
|
||||
when(itemView.findViewById(android.R.id.summary)).thenReturn(mock(TextView.class));
|
||||
final DashboardAdapterV2.SuggestionContainerHolder holder =
|
||||
new DashboardAdapterV2.SuggestionContainerHolder(itemView);
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1", "pkg2", "pkg3", "pkg4");
|
||||
final DashboardAdapterV2 adapter = spy(new DashboardAdapterV2(mContext,
|
||||
null /*savedInstance */, null /* conditions */, null /* suggestionControllerMixin */,
|
||||
null /* lifecycle */));
|
||||
adapter.setSuggestions(suggestions);
|
||||
adapter.onBindSuggestion(holder, 0);
|
||||
|
||||
adapter.onSuggestionClosed(suggestions.get(1));
|
||||
|
||||
// verify operations that access the lists will not cause ConcurrentModificationException
|
||||
assertThat(holder.data.getAdapter().getItemCount()).isEqualTo(3);
|
||||
adapter.setSuggestions(suggestions);
|
||||
// should not crash
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestionDismissed_onlySuggestion_updateDashboardData() {
|
||||
DashboardAdapterV2 adapter =
|
||||
spy(new DashboardAdapterV2(mContext, null /* savedInstanceState */,
|
||||
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */));
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
|
||||
adapter.setSuggestions(suggestions);
|
||||
final DashboardDataV2 dashboardData = adapter.mDashboardData;
|
||||
reset(adapter); // clear interactions tracking
|
||||
|
||||
adapter.onSuggestionClosed(suggestions.get(0));
|
||||
|
||||
assertThat(adapter.mDashboardData).isNotEqualTo(dashboardData);
|
||||
verify(adapter).notifyDashboardDataChanged(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCategories_iconTinted() {
|
||||
TypedArray mockTypedArray = mock(TypedArray.class);
|
||||
doReturn(mockTypedArray).when(mContext).obtainStyledAttributes(any(int[].class));
|
||||
doReturn(0x89000000).when(mockTypedArray).getColor(anyInt(), anyInt());
|
||||
|
||||
final DashboardCategory category = new DashboardCategory();
|
||||
final Icon mockIcon = mock(Icon.class);
|
||||
final Tile tile = new Tile();
|
||||
tile.isIconTintable = true;
|
||||
tile.icon = mockIcon;
|
||||
category.addTile(tile);
|
||||
|
||||
mDashboardAdapter.setCategory(category);
|
||||
|
||||
verify(mockIcon).setTint(eq(0x89000000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindSuggestion_shouldSetSuggestionAdapterAndNoCrash() {
|
||||
mDashboardAdapter = new DashboardAdapterV2(mContext, null /* savedInstanceState */,
|
||||
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
|
||||
|
||||
mDashboardAdapter.setSuggestions(suggestions);
|
||||
|
||||
final RecyclerView data = mock(RecyclerView.class);
|
||||
when(data.getResources()).thenReturn(mResources);
|
||||
when(data.getContext()).thenReturn(mContext);
|
||||
when(mResources.getDisplayMetrics()).thenReturn(mock(DisplayMetrics.class));
|
||||
final View itemView = mock(View.class);
|
||||
when(itemView.findViewById(R.id.suggestion_list)).thenReturn(data);
|
||||
when(itemView.findViewById(android.R.id.summary)).thenReturn(mock(TextView.class));
|
||||
final DashboardAdapterV2.SuggestionContainerHolder holder =
|
||||
new DashboardAdapterV2.SuggestionContainerHolder(itemView);
|
||||
|
||||
mDashboardAdapter.onBindSuggestion(holder, 0);
|
||||
|
||||
verify(data).setAdapter(any(SuggestionAdapterV2.class));
|
||||
// should not crash
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindSuggestion_shouldSetSummary() {
|
||||
mDashboardAdapter = new DashboardAdapterV2(mContext, null /* savedInstanceState */,
|
||||
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
|
||||
|
||||
mDashboardAdapter.setSuggestions(suggestions);
|
||||
|
||||
final RecyclerView data = mock(RecyclerView.class);
|
||||
when(data.getResources()).thenReturn(mResources);
|
||||
when(data.getContext()).thenReturn(mContext);
|
||||
when(mResources.getDisplayMetrics()).thenReturn(mock(DisplayMetrics.class));
|
||||
final View itemView = mock(View.class);
|
||||
when(itemView.findViewById(R.id.suggestion_list)).thenReturn(data);
|
||||
final TextView summary = mock(TextView.class);
|
||||
when(itemView.findViewById(android.R.id.summary)).thenReturn(summary);
|
||||
final DashboardAdapterV2.SuggestionContainerHolder holder =
|
||||
new DashboardAdapterV2.SuggestionContainerHolder(itemView);
|
||||
|
||||
mDashboardAdapter.onBindSuggestion(holder, 0);
|
||||
|
||||
verify(summary).setText("1");
|
||||
|
||||
suggestions.addAll(makeSuggestionsV2("pkg2", "pkg3", "pkg4"));
|
||||
mDashboardAdapter.setSuggestions(suggestions);
|
||||
|
||||
mDashboardAdapter.onBindSuggestion(holder, 0);
|
||||
|
||||
verify(summary).setText("4");
|
||||
}
|
||||
|
||||
private List<Suggestion> makeSuggestionsV2(String... pkgNames) {
|
||||
final List<Suggestion> suggestions = new ArrayList<>();
|
||||
for (String pkgName : pkgNames) {
|
||||
final Suggestion suggestion = new Suggestion.Builder(pkgName)
|
||||
.setPendingIntent(mock(PendingIntent.class))
|
||||
.build();
|
||||
suggestions.add(suggestion);
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
private void setupSuggestions(List<Suggestion> suggestions) {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
mDashboardAdapter.setSuggestions(suggestions);
|
||||
}
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.conditional;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.dashboard.DashboardAdapterV2;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class ConditionAdapterV2Test {
|
||||
@Mock
|
||||
private Condition mCondition1;
|
||||
@Mock
|
||||
private Condition mCondition2;
|
||||
|
||||
private Context mContext;
|
||||
private ConditionAdapterV2 mConditionAdapter;
|
||||
private List<Condition> mOneCondition;
|
||||
private List<Condition> mTwoConditions;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
final CharSequence[] actions = new CharSequence[2];
|
||||
when(mCondition1.getActions()).thenReturn(actions);
|
||||
when(mCondition1.shouldShow()).thenReturn(true);
|
||||
mOneCondition = new ArrayList<>();
|
||||
mOneCondition.add(mCondition1);
|
||||
mTwoConditions = new ArrayList<>();
|
||||
mTwoConditions.add(mCondition1);
|
||||
mTwoConditions.add(mCondition2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemCount_notExpanded_shouldReturn0() {
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mOneCondition, false);
|
||||
assertThat(mConditionAdapter.getItemCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemCount_expanded_shouldReturnListSize() {
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mOneCondition, true);
|
||||
assertThat(mConditionAdapter.getItemCount()).isEqualTo(1);
|
||||
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mTwoConditions, true);
|
||||
assertThat(mConditionAdapter.getItemCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemViewType_shouldReturnConditionTile() {
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mTwoConditions, true);
|
||||
assertThat(mConditionAdapter.getItemViewType(0)).isEqualTo(R.layout.condition_tile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_shouldSetListener() {
|
||||
final View view = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.condition_tile, new LinearLayout(mContext), true);
|
||||
final DashboardAdapterV2.DashboardItemHolder viewHolder =
|
||||
new DashboardAdapterV2.DashboardItemHolder(view);
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mOneCondition, true);
|
||||
|
||||
mConditionAdapter.onBindViewHolder(viewHolder, 0);
|
||||
final View card = view.findViewById(R.id.content);
|
||||
assertThat(card.hasOnClickListeners()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void viewClick_shouldInvokeConditionPrimaryClick() {
|
||||
final View view = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.condition_tile, new LinearLayout(mContext), true);
|
||||
final DashboardAdapterV2.DashboardItemHolder viewHolder =
|
||||
new DashboardAdapterV2.DashboardItemHolder(view);
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mOneCondition, true);
|
||||
|
||||
mConditionAdapter.onBindViewHolder(viewHolder, 0);
|
||||
final View card = view.findViewById(R.id.content);
|
||||
card.performClick();
|
||||
verify(mCondition1).onPrimaryClick();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwiped_nullCondition_shouldNotCrash() {
|
||||
final RecyclerView recyclerView = new RecyclerView(mContext);
|
||||
final View view = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.condition_tile, new LinearLayout(mContext), true);
|
||||
final DashboardAdapterV2.DashboardItemHolder viewHolder =
|
||||
new DashboardAdapterV2.DashboardItemHolder(view);
|
||||
mConditionAdapter = new ConditionAdapterV2(mContext, mOneCondition, true);
|
||||
mConditionAdapter.addDismissHandling(recyclerView);
|
||||
|
||||
// do not bind viewholder to simulate the null condition scenario
|
||||
mConditionAdapter.mSwipeCallback.onSwiped(viewHolder, 0);
|
||||
// no crash
|
||||
}
|
||||
|
||||
}
|
@@ -36,7 +36,6 @@ import com.android.settings.TestConfig;
|
||||
import com.android.settings.dashboard.DashboardAdapter;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settingslib.drawer.Tile;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -62,10 +61,8 @@ public class SuggestionAdapterTest {
|
||||
private Context mContext;
|
||||
private SuggestionAdapter mSuggestionAdapter;
|
||||
private DashboardAdapter.DashboardItemHolder mSuggestionHolder;
|
||||
private List<Tile> mOneSuggestion;
|
||||
private List<Tile> mTwoSuggestions;
|
||||
private List<Suggestion> mOneSuggestionV2;
|
||||
private List<Suggestion> mTwoSuggestionsV2;
|
||||
private List<Suggestion> mOneSuggestion;
|
||||
private List<Suggestion> mTwoSuggestions;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -73,45 +70,34 @@ public class SuggestionAdapterTest {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
|
||||
final Tile suggestion1 = new Tile();
|
||||
final Tile suggestion2 = new Tile();
|
||||
final Suggestion suggestion1V2 = new Suggestion.Builder("id1")
|
||||
final Suggestion suggestion1 = new Suggestion.Builder("id1")
|
||||
.setTitle("Test suggestion 1")
|
||||
.build();
|
||||
final Suggestion suggestion2V2 = new Suggestion.Builder("id2")
|
||||
final Suggestion suggestion2 = new Suggestion.Builder("id2")
|
||||
.setTitle("Test suggestion 2")
|
||||
.build();
|
||||
suggestion1.title = "Test Suggestion 1";
|
||||
suggestion1.icon = mock(Icon.class);
|
||||
suggestion2.title = "Test Suggestion 2";
|
||||
suggestion2.icon = mock(Icon.class);
|
||||
mOneSuggestion = new ArrayList<>();
|
||||
mOneSuggestion.add(suggestion1);
|
||||
mTwoSuggestions = new ArrayList<>();
|
||||
mTwoSuggestions.add(suggestion1);
|
||||
mTwoSuggestions.add(suggestion2);
|
||||
mOneSuggestionV2 = new ArrayList<>();
|
||||
mOneSuggestionV2.add(suggestion1V2);
|
||||
mTwoSuggestionsV2 = new ArrayList<>();
|
||||
mTwoSuggestionsV2.add(suggestion1V2);
|
||||
mTwoSuggestionsV2.add(suggestion2V2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemCount_shouldReturnListSize() {
|
||||
mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
|
||||
mOneSuggestionV2, new ArrayList<>());
|
||||
mOneSuggestion, new ArrayList<>());
|
||||
assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(1);
|
||||
|
||||
mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
|
||||
mTwoSuggestionsV2, new ArrayList<>());
|
||||
mTwoSuggestions, new ArrayList<>());
|
||||
assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemViewType_shouldReturnSuggestionTile() {
|
||||
mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
|
||||
mOneSuggestionV2, new ArrayList<>());
|
||||
mOneSuggestion, new ArrayList<>());
|
||||
assertThat(mSuggestionAdapter.getItemViewType(0))
|
||||
.isEqualTo(R.layout.suggestion_tile);
|
||||
}
|
||||
@@ -137,7 +123,7 @@ public class SuggestionAdapterTest {
|
||||
R.layout.suggestion_tile, new LinearLayout(mContext), true));
|
||||
mSuggestionHolder = new DashboardAdapter.DashboardItemHolder(view);
|
||||
mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
|
||||
mOneSuggestionV2, new ArrayList<>());
|
||||
mOneSuggestion, new ArrayList<>());
|
||||
|
||||
// Bind twice
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
@@ -146,13 +132,13 @@ public class SuggestionAdapterTest {
|
||||
// Log once
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, MetricsProto.MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
|
||||
mOneSuggestionV2.get(0).getId());
|
||||
mOneSuggestion.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_itemViewShouldHandleClick()
|
||||
throws PendingIntent.CanceledException {
|
||||
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
|
||||
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
||||
setupSuggestions(mActivity, suggestions);
|
||||
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
@@ -164,21 +150,21 @@ public class SuggestionAdapterTest {
|
||||
|
||||
@Test
|
||||
public void getSuggestions_shouldReturnSuggestionWhenMatch() {
|
||||
final List<Suggestion> suggestionsV2 = makeSuggestionsV2("pkg1");
|
||||
setupSuggestions(mActivity, suggestionsV2);
|
||||
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
||||
setupSuggestions(mActivity, suggestions);
|
||||
|
||||
assertThat(mSuggestionAdapter.getSuggestion(0)).isNotNull();
|
||||
}
|
||||
|
||||
private void setupSuggestions(Context context, List<Suggestion> suggestionsV2) {
|
||||
private void setupSuggestions(Context context, List<Suggestion> suggestions) {
|
||||
mSuggestionAdapter = new SuggestionAdapter(context, mSuggestionControllerMixin,
|
||||
suggestionsV2, new ArrayList<>());
|
||||
suggestions, new ArrayList<>());
|
||||
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
|
||||
new FrameLayout(RuntimeEnvironment.application),
|
||||
mSuggestionAdapter.getItemViewType(0));
|
||||
}
|
||||
|
||||
private List<Suggestion> makeSuggestionsV2(String... pkgNames) {
|
||||
private List<Suggestion> makeSuggestions(String... pkgNames) {
|
||||
final List<Suggestion> suggestions = new ArrayList<>();
|
||||
for (String pkgName : pkgNames) {
|
||||
final Suggestion suggestion = new Suggestion.Builder(pkgName)
|
||||
|
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.service.settings.suggestions.Suggestion;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.dashboard.DashboardAdapterV2;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
public class SuggestionAdapterV2Test {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private SettingsActivity mActivity;
|
||||
@Mock
|
||||
private SuggestionControllerMixin mSuggestionControllerMixin;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
private Context mContext;
|
||||
private SuggestionAdapterV2 mSuggestionAdapter;
|
||||
private DashboardAdapterV2.DashboardItemHolder mSuggestionHolder;
|
||||
private List<Suggestion> mOneSuggestion;
|
||||
private List<Suggestion> mTwoSuggestions;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
|
||||
final Suggestion suggestion1 = new Suggestion.Builder("id1")
|
||||
.setTitle("Test suggestion 1")
|
||||
.build();
|
||||
final Suggestion suggestion2 = new Suggestion.Builder("id2")
|
||||
.setTitle("Test suggestion 2")
|
||||
.build();
|
||||
mOneSuggestion = new ArrayList<>();
|
||||
mOneSuggestion.add(suggestion1);
|
||||
mTwoSuggestions = new ArrayList<>();
|
||||
mTwoSuggestions.add(suggestion1);
|
||||
mTwoSuggestions.add(suggestion2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemCount_shouldReturnListSize() {
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mContext, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(mOneSuggestion);
|
||||
assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(1);
|
||||
|
||||
mSuggestionAdapter.setSuggestions(mTwoSuggestions);
|
||||
assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemViewType_shouldReturnSuggestionTile() {
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mContext, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(mOneSuggestion);
|
||||
assertThat(mSuggestionAdapter.getItemViewType(0))
|
||||
.isEqualTo(R.layout.suggestion_tile_v2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getItemType_hasButton_shouldReturnSuggestionWithButton() {
|
||||
final List<Suggestion> suggestions = new ArrayList<>();
|
||||
suggestions.add(new Suggestion.Builder("id")
|
||||
.setFlags(Suggestion.FLAG_HAS_BUTTON)
|
||||
.setTitle("123")
|
||||
.setSummary("456")
|
||||
.build());
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mContext, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(suggestions);
|
||||
|
||||
assertThat(mSuggestionAdapter.getItemViewType(0))
|
||||
.isEqualTo(R.layout.suggestion_tile_with_button_v2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_shouldLog() {
|
||||
final View view = spy(LayoutInflater.from(mContext).inflate(
|
||||
R.layout.suggestion_tile, new LinearLayout(mContext), true));
|
||||
mSuggestionHolder = new DashboardAdapterV2.DashboardItemHolder(view);
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mContext, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(mOneSuggestion);
|
||||
|
||||
// Bind twice
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
|
||||
// Log once
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, MetricsProto.MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
|
||||
mOneSuggestion.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_itemViewShouldHandleClick()
|
||||
throws PendingIntent.CanceledException {
|
||||
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
||||
setupSuggestions(mActivity, suggestions);
|
||||
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
mSuggestionHolder.itemView.performClick();
|
||||
|
||||
verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
|
||||
verify(suggestions.get(0).getPendingIntent()).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_hasButton_buttonShouldHandleClick()
|
||||
throws PendingIntent.CanceledException {
|
||||
final List<Suggestion> suggestions = new ArrayList<>();
|
||||
final PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||
suggestions.add(new Suggestion.Builder("id")
|
||||
.setFlags(Suggestion.FLAG_HAS_BUTTON)
|
||||
.setTitle("123")
|
||||
.setSummary("456")
|
||||
.setPendingIntent(pendingIntent)
|
||||
.build());
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mContext, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(suggestions);
|
||||
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
|
||||
new FrameLayout(RuntimeEnvironment.application),
|
||||
mSuggestionAdapter.getItemViewType(0));
|
||||
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
mSuggestionHolder.itemView.findViewById(android.R.id.primary).performClick();
|
||||
|
||||
verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
|
||||
verify(pendingIntent).send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSuggestions_shouldReturnSuggestionWhenMatch() {
|
||||
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
||||
setupSuggestions(mActivity, suggestions);
|
||||
|
||||
assertThat(mSuggestionAdapter.getSuggestion(0)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_closeButtonShouldHandleClick()
|
||||
throws PendingIntent.CanceledException {
|
||||
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
||||
final SuggestionAdapterV2.Callback callback = mock(SuggestionAdapterV2.Callback.class);
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(mActivity, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, callback, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(suggestions);
|
||||
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
|
||||
new FrameLayout(RuntimeEnvironment.application),
|
||||
mSuggestionAdapter.getItemViewType(0));
|
||||
|
||||
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
|
||||
mSuggestionHolder.itemView.findViewById(R.id.close_button).performClick();
|
||||
|
||||
verify(callback).onSuggestionClosed(suggestions.get(0));
|
||||
}
|
||||
|
||||
private void setupSuggestions(Context context, List<Suggestion> suggestions) {
|
||||
mSuggestionAdapter = new SuggestionAdapterV2(context, mSuggestionControllerMixin,
|
||||
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
|
||||
mSuggestionAdapter.setSuggestions(suggestions);
|
||||
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
|
||||
new FrameLayout(RuntimeEnvironment.application),
|
||||
mSuggestionAdapter.getItemViewType(0));
|
||||
}
|
||||
|
||||
private List<Suggestion> makeSuggestions(String... pkgNames) {
|
||||
final List<Suggestion> suggestions = new ArrayList<>();
|
||||
for (String pkgName : pkgNames) {
|
||||
final Suggestion suggestion = new Suggestion.Builder(pkgName)
|
||||
.setPendingIntent(mock(PendingIntent.class))
|
||||
.build();
|
||||
suggestions.add(suggestion);
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user