1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.widget; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.eq; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.spy; 24 import static org.mockito.Mockito.times; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.verifyZeroInteractions; 27 import static org.mockito.Mockito.when; 28 29 import android.content.Context; 30 import android.graphics.drawable.ColorDrawable; 31 import android.os.Bundle; 32 import android.support.v7.preference.PreferenceCategory; 33 import android.support.v7.preference.PreferenceScreen; 34 import android.support.v7.preference.PreferenceViewHolder; 35 import android.support.v7.widget.RecyclerView; 36 import android.view.View; 37 38 import com.android.settings.R; 39 import com.android.settings.SettingsActivity; 40 import com.android.settings.SettingsPreferenceFragment; 41 import com.android.settings.testutils.SettingsRobolectricTestRunner; 42 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 import org.robolectric.RuntimeEnvironment; 49 import org.robolectric.util.ReflectionHelpers; 50 51 @RunWith(SettingsRobolectricTestRunner.class) 52 public class HighlightablePreferenceGroupAdapterTest { 53 54 private static final String TEST_KEY = "key"; 55 56 @Mock 57 private View mRoot; 58 @Mock 59 private PreferenceCategory mPreferenceCatetory; 60 @Mock 61 private SettingsPreferenceFragment mFragment; 62 63 private Context mContext; 64 private HighlightablePreferenceGroupAdapter mAdapter; 65 private PreferenceViewHolder mViewHolder; 66 67 @Before 68 public void setUp() { 69 MockitoAnnotations.initMocks(this); 70 mContext = RuntimeEnvironment.application; 71 when(mPreferenceCatetory.getContext()).thenReturn(mContext); 72 mAdapter = spy(new HighlightablePreferenceGroupAdapter(mPreferenceCatetory, TEST_KEY, 73 false /* highlighted*/)); 74 mViewHolder = PreferenceViewHolder.createInstanceForTests( 75 View.inflate(mContext, R.layout.app_preference_item, null)); 76 } 77 78 @Test 79 public void requestHighlight_hasKey_notHighlightedBefore_shouldRequest() { 80 mAdapter.requestHighlight(mRoot, mock(RecyclerView.class)); 81 82 verify(mRoot).postDelayed(any(), 83 eq(HighlightablePreferenceGroupAdapter.DELAY_HIGHLIGHT_DURATION_MILLIS)); 84 } 85 86 @Test 87 public void requestHighlight_noKey_highlightedBefore_noRecyclerView_shouldNotRequest() { 88 ReflectionHelpers.setField(mAdapter, "mHighlightKey", null); 89 ReflectionHelpers.setField(mAdapter, "mHighlightRequested", false); 90 mAdapter.requestHighlight(mRoot, mock(RecyclerView.class)); 91 92 ReflectionHelpers.setField(mAdapter, "mHighlightKey", TEST_KEY); 93 ReflectionHelpers.setField(mAdapter, "mHighlightRequested", true); 94 mAdapter.requestHighlight(mRoot, mock(RecyclerView.class)); 95 96 ReflectionHelpers.setField(mAdapter, "mHighlightKey", TEST_KEY); 97 ReflectionHelpers.setField(mAdapter, "mHighlightRequested", false); 98 mAdapter.requestHighlight(mRoot, null /* recyclerView */); 99 100 verifyZeroInteractions(mRoot); 101 } 102 103 @Test 104 public void adjustInitialExpandedChildCount_invalidInput_shouldNotadjust() { 105 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(null /* host */); 106 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 107 final Bundle args = new Bundle(); 108 when(mFragment.getArguments()).thenReturn(args); 109 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 110 final PreferenceScreen screen = mock(PreferenceScreen.class); 111 when(mFragment.getArguments()).thenReturn(null); 112 when(mFragment.getPreferenceScreen()).thenReturn(screen); 113 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 114 verifyZeroInteractions(screen); 115 } 116 117 @Test 118 public void adjustInitialExpandedChildCount_hasHightlightKey_shouldExpandAllChildren() { 119 final Bundle args = new Bundle(); 120 when(mFragment.getArguments()).thenReturn(args); 121 args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, "testkey"); 122 final PreferenceScreen screen = mock(PreferenceScreen.class); 123 when(mFragment.getPreferenceScreen()).thenReturn(screen); 124 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 125 126 verify(screen).setInitialExpandedChildrenCount(Integer.MAX_VALUE); 127 } 128 129 @Test 130 public void adjustInitialExpandedChildCount_noKeyOrChildCountOverride_shouldDoNothing() { 131 final Bundle args = new Bundle(); 132 when(mFragment.getArguments()).thenReturn(args); 133 when(mFragment.getInitialExpandedChildCount()).thenReturn(-1); 134 final PreferenceScreen screen = mock(PreferenceScreen.class); 135 when(mFragment.getPreferenceScreen()).thenReturn(screen); 136 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 137 138 verify(mFragment).getInitialExpandedChildCount(); 139 verifyZeroInteractions(screen); 140 } 141 142 @Test 143 public void adjustInitialExpandedChildCount_hasCountOverride_shouldDoNothing() { 144 when(mFragment.getInitialExpandedChildCount()).thenReturn(10); 145 final PreferenceScreen screen = mock(PreferenceScreen.class); 146 when(mFragment.getPreferenceScreen()).thenReturn(screen); 147 HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(mFragment); 148 149 verify(mFragment).getInitialExpandedChildCount(); 150 151 verify(screen).setInitialExpandedChildrenCount(10); 152 } 153 154 @Test 155 public void updateBackground_notHighlightedRow_shouldNotSetHighlightedTag() { 156 ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10); 157 158 mAdapter.updateBackground(mViewHolder, 0); 159 160 assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isNull(); 161 } 162 163 @Test 164 public void updateBackground_highlight_shouldAnimateBackgroundAndSetHighlightedTag() { 165 ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10); 166 assertThat(mAdapter.mFadeInAnimated).isFalse(); 167 168 mAdapter.updateBackground(mViewHolder, 10); 169 170 assertThat(mAdapter.mFadeInAnimated).isTrue(); 171 assertThat(mViewHolder.itemView.getBackground()).isInstanceOf(ColorDrawable.class); 172 assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isEqualTo(true); 173 verify(mAdapter).requestRemoveHighlightDelayed(mViewHolder.itemView); 174 } 175 176 @Test 177 public void updateBackgroundTwice_highlight_shouldAnimateOnce() { 178 ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10); 179 ReflectionHelpers.setField(mViewHolder, "itemView", spy(mViewHolder.itemView)); 180 assertThat(mAdapter.mFadeInAnimated).isFalse(); 181 mAdapter.updateBackground(mViewHolder, 10); 182 // mFadeInAnimated change from false to true - indicating background change is scheduled 183 // through animation. 184 assertThat(mAdapter.mFadeInAnimated).isTrue(); 185 // remove highlight should be requested. 186 verify(mAdapter).requestRemoveHighlightDelayed(mViewHolder.itemView); 187 188 ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10); 189 mAdapter.updateBackground(mViewHolder, 10); 190 // only sets background color once - if it's animation this would be called many times 191 verify(mViewHolder.itemView).setBackgroundColor(mAdapter.mHighlightColor); 192 // remove highlight should be requested. 193 verify(mAdapter, times(2)).requestRemoveHighlightDelayed(mViewHolder.itemView); 194 } 195 196 @Test 197 public void updateBackground_reuseHightlightedRowForNormalRow_shouldResetBackgroundAndTag() { 198 ReflectionHelpers.setField(mAdapter, "mHighlightPosition", 10); 199 mViewHolder.itemView.setTag(R.id.preference_highlighted, true); 200 201 mAdapter.updateBackground(mViewHolder, 0); 202 203 assertThat(mViewHolder.itemView.getBackground()).isNotInstanceOf(ColorDrawable.class); 204 assertThat(mViewHolder.itemView.getTag(R.id.preference_highlighted)).isEqualTo(false); 205 } 206 } 207