blob: dc492a9390715ed3adf7b7caac043e0e54a46976 [file] [log] [blame]
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
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.Drawable;
import android.graphics.drawable.Icon;
import android.service.settings.suggestions.Suggestion;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
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.dashboard.DashboardAdapter;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowCardView;
import com.android.settingslib.suggestions.SuggestionControllerMixin;
import com.android.settingslib.utils.IconCache;
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 org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = ShadowCardView.class)
public class SuggestionAdapterTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private SettingsActivity mActivity;
@Mock
private SuggestionControllerMixin mSuggestionControllerMixin;
@Mock
private Resources mResources;
@Mock
private WindowManager mWindowManager;
private FakeFeatureFactory mFeatureFactory;
private Context mContext;
private SuggestionAdapter mSuggestionAdapter;
private DashboardAdapter.DashboardItemHolder mSuggestionHolder;
private List<Suggestion> mOneSuggestion;
private List<Suggestion> mTwoSuggestions;
private SuggestionAdapter.CardConfig mConfig;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mActivity.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
when(mActivity.getResources()).thenReturn(mResources);
when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin))
.thenReturn(10);
when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin))
.thenReturn(20);
mConfig = spy(SuggestionAdapter.CardConfig.get(mActivity));
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 SuggestionAdapter(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 SuggestionAdapter(mContext, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(mOneSuggestion);
assertThat(mSuggestionAdapter.getItemViewType(0))
.isEqualTo(R.layout.suggestion_tile);
}
@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 SuggestionAdapter(mContext, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(suggestions);
assertThat(mSuggestionAdapter.getItemViewType(0))
.isEqualTo(R.layout.suggestion_tile_with_button);
}
@Test
public void onBindViewHolder_shouldLog() {
final View view = spy(LayoutInflater.from(mContext).inflate(
R.layout.suggestion_tile, new LinearLayout(mContext), true));
mSuggestionHolder = new DashboardAdapter.DashboardItemHolder(view);
mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(mOneSuggestion);
doReturn("sans").when(mContext).getString(anyInt());
// 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 SuggestionAdapter(mContext, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(suggestions);
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
new FrameLayout(RuntimeEnvironment.application),
mSuggestionAdapter.getItemViewType(0));
doReturn("sans").when(mContext).getString(anyInt());
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 SuggestionAdapter.Callback callback = mock(SuggestionAdapter.Callback.class);
mSuggestionAdapter = new SuggestionAdapter(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();
final Suggestion suggestion = suggestions.get(0);
verify(mFeatureFactory.suggestionsFeatureProvider).dismissSuggestion(
mActivity, mSuggestionControllerMixin, suggestion);
verify(callback).onSuggestionClosed(suggestion);
}
@Test
public void onBindViewHolder_iconNotTintable_shouldNotTintIcon()
throws PendingIntent.CanceledException {
final Icon icon = mock(Icon.class);
final Suggestion suggestion = new Suggestion.Builder("pkg1")
.setPendingIntent(mock(PendingIntent.class))
.setIcon(icon)
.build();
final List<Suggestion> suggestions = new ArrayList<>();
suggestions.add(suggestion);
mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(suggestions);
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
new FrameLayout(RuntimeEnvironment.application),
mSuggestionAdapter.getItemViewType(0));
IconCache cache = mock(IconCache.class);
final Drawable drawable = mock(Drawable.class);
when(cache.getIcon(icon)).thenReturn(drawable);
ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
verify(drawable, never()).setTint(anyInt());
}
@Test
public void onBindViewHolder_iconTintable_shouldTintIcon()
throws PendingIntent.CanceledException {
final Icon icon = mock(Icon.class);
final int FLAG_ICON_TINTABLE = 1 << 1;
final Suggestion suggestion = new Suggestion.Builder("pkg1")
.setPendingIntent(mock(PendingIntent.class))
.setIcon(icon)
.setFlags(FLAG_ICON_TINTABLE)
.build();
final List<Suggestion> suggestions = new ArrayList<>();
suggestions.add(suggestion);
mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
mSuggestionAdapter.setSuggestions(suggestions);
mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
new FrameLayout(RuntimeEnvironment.application),
mSuggestionAdapter.getItemViewType(0));
IconCache cache = mock(IconCache.class);
final Drawable drawable = mock(Drawable.class);
when(cache.getIcon(icon)).thenReturn(drawable);
ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
TypedArray typedArray = mock(TypedArray.class);
final int colorAccent = 1234;
when(mActivity.obtainStyledAttributes(any())).thenReturn(typedArray);
when(typedArray.getColor(anyInt(), anyInt())).thenReturn(colorAccent);
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
verify(drawable).setTint(colorAccent);
}
@Test
public void onBindViewHolder_closeButtonShouldHaveContentDescription()
throws PendingIntent.CanceledException {
final List<Suggestion> suggestions = makeSuggestions("pkg1");
setupSuggestions(mActivity, suggestions);
mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
assertThat(
mSuggestionHolder.itemView.findViewById(R.id.close_button).getContentDescription())
.isNotNull();
}
@Test
public void setCardLayout_twoCards_shouldSetCardWidthToHalfScreenMinusPadding() {
final List<Suggestion> suggestions = makeSuggestions("pkg1");
setupSuggestions(mContext, suggestions);
doReturn(200).when(mConfig).getScreenWidth();
mConfig.setCardLayout(mSuggestionHolder, 0);
/*
* card width = (screen width - left margin - inner margin - right margin) / 2
* = (200 - 20 - 10 - 20) / 2
* = 75
*/
assertThat(mSuggestionHolder.itemView.getLayoutParams().width).isEqualTo(75);
}
private void setupSuggestions(Context context, List<Suggestion> suggestions) {
mSuggestionAdapter = new SuggestionAdapter(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;
}
}