And switch to getId() instead of title when comparing 2 tiles. This is more accurate and more efficient. Bug: 77600770 Test: robotests Change-Id: I587d90702d98956bf7b420529ac3280351ca4a10
288 lines
13 KiB
Java
288 lines
13 KiB
Java
/*
|
|
* 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.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
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.pm.ActivityInfo;
|
|
import android.content.res.Resources;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.Icon;
|
|
import android.os.Bundle;
|
|
import android.service.settings.suggestions.Suggestion;
|
|
import android.util.DisplayMetrics;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.SettingsActivity;
|
|
import com.android.settings.homepage.conditional.Condition;
|
|
import com.android.settings.dashboard.suggestions.SuggestionAdapter;
|
|
import com.android.settings.testutils.FakeFeatureFactory;
|
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
|
import com.android.settings.widget.RoundedHomepageIcon;
|
|
import com.android.settingslib.drawer.CategoryKey;
|
|
import com.android.settingslib.drawer.Tile;
|
|
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 = SettingsShadowResources.SettingsShadowTheme.class)
|
|
public class DashboardAdapterTest {
|
|
|
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
|
private SettingsActivity mContext;
|
|
@Mock
|
|
private View mView;
|
|
@Mock
|
|
private Condition mCondition;
|
|
@Mock
|
|
private Resources mResources;
|
|
@Mock
|
|
private WindowManager mWindowManager;
|
|
private ActivityInfo mActivityInfo;
|
|
private FakeFeatureFactory mFactory;
|
|
private DashboardAdapter mDashboardAdapter;
|
|
private List<Condition> mConditionList;
|
|
|
|
@Before
|
|
public void setUp() {
|
|
MockitoAnnotations.initMocks(this);
|
|
mFactory = FakeFeatureFactory.setupForTest();
|
|
mActivityInfo = new ActivityInfo();
|
|
mActivityInfo.packageName = "pkg";
|
|
mActivityInfo.name = "class";
|
|
mActivityInfo.metaData = new Bundle();
|
|
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_TITLE, "test-title");
|
|
|
|
when(mContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
|
|
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 DashboardAdapter(mContext, null /* savedInstanceState */,
|
|
mConditionList, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */);
|
|
when(mView.getTag()).thenReturn(mCondition);
|
|
}
|
|
|
|
@Test
|
|
public void onSuggestionClosed_notOnlySuggestion_updateSuggestionOnly() {
|
|
final DashboardAdapter adapter =
|
|
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */,
|
|
null /* lifecycle */));
|
|
final List<Suggestion> suggestions = makeSuggestions("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));
|
|
when(itemView.findViewById(android.R.id.title)).thenReturn(mock(TextView.class));
|
|
final DashboardAdapter.SuggestionContainerHolder holder =
|
|
new DashboardAdapter.SuggestionContainerHolder(itemView);
|
|
|
|
adapter.onBindSuggestion(holder, 0);
|
|
|
|
reset(adapter); // clear interactions tracking
|
|
|
|
final Suggestion suggestionToRemove = suggestions.get(1);
|
|
adapter.onSuggestionClosed(suggestionToRemove);
|
|
|
|
assertThat(suggestions.size()).isEqualTo(2);
|
|
assertThat(suggestions.contains(suggestionToRemove)).isFalse();
|
|
verify(adapter).notifyDashboardDataChanged(any());
|
|
}
|
|
|
|
@Test
|
|
public void onSuggestionClosed_onlySuggestion_updateDashboardData() {
|
|
final DashboardAdapter adapter =
|
|
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */));
|
|
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
|
adapter.setSuggestions(suggestions);
|
|
final DashboardData 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 onSuggestionClosed_notInSuggestionList_shouldNotUpdateSuggestionList() {
|
|
final DashboardAdapter adapter =
|
|
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */));
|
|
final List<Suggestion> suggestions = makeSuggestions("pkg1");
|
|
adapter.setSuggestions(suggestions);
|
|
|
|
reset(adapter); // clear interactions tracking
|
|
|
|
adapter.onSuggestionClosed(mock(Suggestion.class));
|
|
|
|
verify(adapter, never()).setSuggestions(any());
|
|
}
|
|
|
|
@Test
|
|
public void onBindSuggestion_shouldSetSuggestionAdapterAndNoCrash() {
|
|
mDashboardAdapter = new DashboardAdapter(mContext, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */);
|
|
final List<Suggestion> suggestions = makeSuggestions("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));
|
|
when(itemView.findViewById(android.R.id.title)).thenReturn(mock(TextView.class));
|
|
final DashboardAdapter.SuggestionContainerHolder holder =
|
|
new DashboardAdapter.SuggestionContainerHolder(itemView);
|
|
|
|
mDashboardAdapter.onBindSuggestion(holder, 0);
|
|
|
|
verify(data).setAdapter(any(SuggestionAdapter.class));
|
|
// should not crash
|
|
}
|
|
|
|
@Test
|
|
public void onBindTile_internalTile_shouldNotUseGenericBackgroundIcon() {
|
|
final Context context = RuntimeEnvironment.application;
|
|
final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
|
|
final DashboardAdapter.DashboardItemHolder holder =
|
|
new DashboardAdapter.DashboardItemHolder(view);
|
|
final Tile tile = spy(new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
|
|
doReturn(Icon.createWithResource(context, R.drawable.ic_settings))
|
|
.when(tile).getIcon(context);
|
|
final IconCache iconCache = mock(IconCache.class);
|
|
when(iconCache.getIcon(tile.getIcon(context)))
|
|
.thenReturn(context.getDrawable(R.drawable.ic_settings));
|
|
|
|
mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */);
|
|
ReflectionHelpers.setField(mDashboardAdapter, "mCache", iconCache);
|
|
mDashboardAdapter.onBindTile(holder, tile);
|
|
|
|
verify(iconCache, never()).updateIcon(any(Icon.class), any(Drawable.class));
|
|
}
|
|
|
|
@Test
|
|
public void onBindTile_externalTile_shouldUpdateIcon() {
|
|
final Context context = spy(RuntimeEnvironment.application);
|
|
final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
|
|
final DashboardAdapter.DashboardItemHolder holder =
|
|
new DashboardAdapter.DashboardItemHolder(view);
|
|
final Tile tile = spy(new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
|
|
final Icon icon = Icon.createWithResource(context, R.drawable.ic_settings);
|
|
doReturn(icon).when(tile).getIcon(context);
|
|
|
|
final IconCache iconCache = new IconCache(context);
|
|
|
|
mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */);
|
|
ReflectionHelpers.setField(mDashboardAdapter, "mCache", iconCache);
|
|
|
|
doReturn("another.package").when(context).getPackageName();
|
|
mDashboardAdapter.onBindTile(holder, tile);
|
|
|
|
assertThat(iconCache.getIcon(tile.getIcon(context)))
|
|
.isInstanceOf(RoundedHomepageIcon.class);
|
|
}
|
|
|
|
@Test
|
|
public void onBindTile_externalTile_usingRoundedHomepageIcon_shouldNotUpdateIcon() {
|
|
final Context context = RuntimeEnvironment.application;
|
|
final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
|
|
final DashboardAdapter.DashboardItemHolder holder =
|
|
new DashboardAdapter.DashboardItemHolder(view);
|
|
final Tile tile = spy(new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
|
|
doReturn(mock(Icon.class)).when(tile).getIcon(context);
|
|
when(tile.getIcon(context).getResPackage()).thenReturn("another.package");
|
|
|
|
final IconCache iconCache = mock(IconCache.class);
|
|
when(iconCache.getIcon(tile.getIcon(context))).thenReturn(mock(RoundedHomepageIcon.class));
|
|
|
|
mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
|
|
null /* conditions */, null /* conditionManager */,
|
|
null /* suggestionControllerMixin */, null /* lifecycle */);
|
|
ReflectionHelpers.setField(mDashboardAdapter, "mCache", iconCache);
|
|
|
|
mDashboardAdapter.onBindTile(holder, tile);
|
|
|
|
verify(iconCache, never()).updateIcon(eq(tile.getIcon(context)),
|
|
any(RoundedHomepageIcon.class));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|