1 /* 2 * Copyright (C) 2016 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.dashboard; 18 19 import android.content.Context; 20 import android.support.v14.preference.PreferenceFragment; 21 import android.support.v7.preference.Preference; 22 import android.support.v7.preference.PreferenceManager; 23 import android.support.v7.preference.PreferenceScreen; 24 25 import com.android.settings.R; 26 import com.android.settings.testutils.SettingsRobolectricTestRunner; 27 import com.android.settings.TestConfig; 28 import com.android.settings.testutils.FakeFeatureFactory; 29 30 import org.junit.Before; 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 import org.mockito.Answers; 34 import org.mockito.Mock; 35 import org.mockito.MockitoAnnotations; 36 import org.robolectric.annotation.Config; 37 import org.robolectric.shadows.ShadowApplication; 38 import org.robolectric.util.ReflectionHelpers; 39 40 import java.util.List; 41 42 import static com.google.common.truth.Truth.assertThat; 43 44 import static org.mockito.ArgumentMatchers.nullable; 45 import static org.mockito.Matchers.any; 46 import static org.mockito.Matchers.anyInt; 47 import static org.mockito.Mockito.atLeastOnce; 48 import static org.mockito.Mockito.mock; 49 import static org.mockito.Mockito.never; 50 import static org.mockito.Mockito.spy; 51 import static org.mockito.Mockito.times; 52 import static org.mockito.Mockito.verify; 53 import static org.mockito.Mockito.when; 54 55 @RunWith(SettingsRobolectricTestRunner.class) 56 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 57 public class ProgressiveDisclosureTest { 58 59 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 60 private Context mContext; 61 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 62 private PreferenceFragment mPreferenceFragment; 63 @Mock 64 private ExpandPreference mExpandButton; 65 private PreferenceScreen mScreen; 66 private Context mAppContext; 67 private Preference mPreference; 68 private ProgressiveDisclosureMixin mMixin; 69 70 @Before setUp()71 public void setUp() { 72 MockitoAnnotations.initMocks(this); 73 FakeFeatureFactory.setupForTest(mContext); 74 mScreen = mPreferenceFragment.getPreferenceScreen(); 75 mAppContext = ShadowApplication.getInstance().getApplicationContext(); 76 mMixin = new ProgressiveDisclosureMixin(mAppContext, 77 mPreferenceFragment, false /* keepExpanded */); 78 ReflectionHelpers.setField(mMixin, "mExpandButton", mExpandButton); 79 mPreference = new Preference(mAppContext); 80 mPreference.setKey("test"); 81 } 82 83 @Test shouldNotCollapse_lessPreferenceThanLimit()84 public void shouldNotCollapse_lessPreferenceThanLimit() { 85 when(mScreen.getPreferenceCount()).thenReturn(5); 86 87 mMixin.setTileLimit(10); 88 89 assertThat(mMixin.shouldCollapse(mScreen)).isFalse(); 90 } 91 92 @Test shouldNotCollapse_preferenceCountSameAsThreshold()93 public void shouldNotCollapse_preferenceCountSameAsThreshold() { 94 when(mScreen.getPreferenceCount()).thenReturn(5); 95 96 mMixin.setTileLimit(5); 97 98 assertThat(mMixin.shouldCollapse(mScreen)).isFalse(); 99 } 100 101 @Test shouldNotCollapse_whenStartAsExpanded()102 public void shouldNotCollapse_whenStartAsExpanded() { 103 when(mScreen.getPreferenceCount()).thenReturn(5); 104 105 mMixin = new ProgressiveDisclosureMixin(mAppContext, 106 mPreferenceFragment, true /* keepExpanded */); 107 mMixin.setTileLimit(10); 108 109 assertThat(mMixin.shouldCollapse(mScreen)).isFalse(); 110 } 111 112 @Test shouldCollapse_morePreferenceThanLimit()113 public void shouldCollapse_morePreferenceThanLimit() { 114 when(mScreen.getPreferenceCount()).thenReturn(5); 115 mMixin.setTileLimit(3); 116 117 assertThat(mMixin.shouldCollapse(mScreen)).isTrue(); 118 } 119 120 @Test findPreference_prefInCollapsedList_shouldFindIt()121 public void findPreference_prefInCollapsedList_shouldFindIt() { 122 when(mScreen.findPreference(nullable(String.class))).thenReturn(null); 123 mMixin.addToCollapsedList(mPreference); 124 125 Preference pref = mMixin.findPreference(mScreen, mPreference.getKey()); 126 127 assertThat(pref).isNotNull(); 128 assertThat(pref).isSameAs(mPreference); 129 } 130 131 @Test findPreference_prefOnScreen_shouldFindIt()132 public void findPreference_prefOnScreen_shouldFindIt() { 133 when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); 134 135 Preference pref = mMixin.findPreference(mScreen, mPreference.getKey()); 136 137 assertThat(pref).isNotNull(); 138 assertThat(pref).isSameAs(mPreference); 139 } 140 141 @Test findPreference_prefNotInCollapsedListOrScreen_shouldNotFindIt()142 public void findPreference_prefNotInCollapsedListOrScreen_shouldNotFindIt() { 143 when(mScreen.findPreference(nullable(String.class))).thenReturn(null); 144 Preference pref = mMixin.findPreference(mScreen, mPreference.getKey()); 145 146 assertThat(pref).isNull(); 147 } 148 149 @Test findPreference_prefRemovedFromCollapsedList_shouldNotFindIt()150 public void findPreference_prefRemovedFromCollapsedList_shouldNotFindIt() { 151 when(mScreen.findPreference(nullable(String.class))).thenReturn(null); 152 mMixin.addToCollapsedList(mPreference); 153 mMixin.removePreference(mPreferenceFragment.getPreferenceScreen(), mPreference.getKey()); 154 155 Preference pref = mMixin.findPreference(mScreen, mPreference.getKey()); 156 157 assertThat(pref).isNull(); 158 } 159 160 @Test findPreference_nestedPrefInCollapsedList_shouldFindIt()161 public void findPreference_nestedPrefInCollapsedList_shouldFindIt() { 162 when(mScreen.findPreference(nullable(String.class))).thenReturn(null); 163 final PreferenceScreen prefGroup = spy(new PreferenceScreen(mAppContext, null)); 164 when(prefGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class)); 165 final Preference preference = mock(Preference.class); 166 when(preference.getKey()).thenReturn("TestKey"); 167 prefGroup.addPreference(preference); 168 mMixin.addToCollapsedList(prefGroup); 169 170 Preference pref = mMixin.findPreference(mScreen, "TestKey"); 171 172 assertThat(pref).isNotNull(); 173 assertThat(pref).isSameAs(preference); 174 } 175 176 @Test removePreference_shouldRemoveOnScreenPreference()177 public void removePreference_shouldRemoveOnScreenPreference() { 178 when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); 179 180 mMixin.removePreference(mScreen, mPreference.getKey()); 181 182 verify(mScreen).removePreference(mPreference); 183 } 184 185 @Test removeLastPreference_shouldRemoveExpandButtonToo()186 public void removeLastPreference_shouldRemoveExpandButtonToo() { 187 when(mScreen.findPreference(nullable(String.class))).thenReturn(null); 188 mMixin.addToCollapsedList(mPreference); 189 // Collapsed 190 assertThat(mMixin.isCollapsed()).isTrue(); 191 192 mMixin.removePreference(mScreen, mPreference.getKey()); 193 194 // Removing expand button 195 verify(mScreen).removePreference(any(Preference.class)); 196 // No longer collapsed 197 assertThat(mMixin.isCollapsed()).isFalse(); 198 } 199 200 @Test collapse_shouldDoNothingIfNotCollapsible()201 public void collapse_shouldDoNothingIfNotCollapsible() { 202 final PreferenceScreen screen = mPreferenceFragment.getPreferenceScreen(); 203 when(screen.getPreferenceCount()).thenReturn(5); 204 mMixin.setTileLimit(15); 205 206 mMixin.collapse(screen); 207 assertThat(mMixin.isCollapsed()).isFalse(); 208 verify(mExpandButton, never()).setSummary(nullable(String.class)); 209 verify(screen, never()).addPreference(any(Preference.class)); 210 verify(screen, never()).removePreference(any(Preference.class)); 211 } 212 213 @Test collapse_shouldRemovePrefAndAddExpandButton()214 public void collapse_shouldRemovePrefAndAddExpandButton() { 215 final PreferenceScreen screen = mPreferenceFragment.getPreferenceScreen(); 216 when(screen.getPreferenceCount()).thenReturn(5); 217 when(screen.getPreference(anyInt())).thenReturn(mPreference); 218 mMixin.setTileLimit(2); 219 220 mMixin.collapse(screen); 221 222 assertThat(mMixin.isCollapsed()).isTrue(); 223 verify(mExpandButton, atLeastOnce()).setSummary(nullable(String.class)); 224 verify(screen).addPreference(any(ExpandPreference.class)); 225 verify(screen, times(3)).removePreference(any(Preference.class)); 226 } 227 228 @Test addToCollapsedList_shouldAddInOrder()229 public void addToCollapsedList_shouldAddInOrder() { 230 final Preference pref1 = new Preference(mAppContext); 231 final Preference pref2 = new Preference(mAppContext); 232 pref1.setOrder(10); 233 pref2.setOrder(20); 234 235 // Pref1 has lower order than pref2, but add pref2 first. The collapsed list should maintain 236 // items in increasing order. 237 mMixin.addToCollapsedList(pref2); 238 mMixin.addToCollapsedList(pref1); 239 240 List<Preference> collapsedList = mMixin.getCollapsedPrefs(); 241 assertThat(collapsedList.get(0)).isSameAs(pref1); 242 assertThat(collapsedList.get(1)).isSameAs(pref2); 243 } 244 245 @Test addPreferenceWhenCollapsed_noPrefOnScreen_shouldAddToList()246 public void addPreferenceWhenCollapsed_noPrefOnScreen_shouldAddToList() { 247 // Add something to collapsed list so we are in collapsed state. 248 mMixin.addToCollapsedList(new Preference(mAppContext)); 249 assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1); 250 251 // Just 1 preference on screen: the more button 252 when(mScreen.getPreferenceCount()).thenReturn(1); 253 final Preference toBeAdded = new Preference(mAppContext); 254 toBeAdded.setOrder(100); 255 mMixin.addPreference(mScreen, toBeAdded); 256 257 // Should have 2 prefs in collapsed list now 258 assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(2); 259 assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded); 260 } 261 262 @Test addPreferenceWhenCollapsed_prefOrderLessThanLastOnScreen_shouldAddToScreen()263 public void addPreferenceWhenCollapsed_prefOrderLessThanLastOnScreen_shouldAddToScreen() { 264 final Preference lastPref = new Preference(mAppContext); 265 lastPref.setOrder(100); 266 // Add something to collapsed list so we are in collapsed state. 267 mMixin.addToCollapsedList(new Preference(mAppContext)); 268 verify(mExpandButton).setSummary(nullable(String.class)); 269 assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1); 270 271 // 3 prefs on screen, 2 are real and the last one is more button. 272 when(mScreen.getPreferenceCount()).thenReturn(3); 273 when(mScreen.getPreference(1)).thenReturn(lastPref); 274 275 final Preference toBeAdded = new Preference(mAppContext); 276 toBeAdded.setOrder(50); 277 mMixin.addPreference(mScreen, toBeAdded); 278 279 verify(mScreen).removePreference(lastPref); 280 verify(mScreen).addPreference(toBeAdded); 281 assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(lastPref); 282 } 283 284 @Test addPreferenceWhenCollapsed_prefOrderMoreThanLastOnScreen_shouldAddToList()285 public void addPreferenceWhenCollapsed_prefOrderMoreThanLastOnScreen_shouldAddToList() { 286 final Preference lastPref = new Preference(mAppContext); 287 lastPref.setOrder(100); 288 // Add something to collapsed list so we are in collapsed state. 289 mMixin.addToCollapsedList(new Preference(mAppContext)); 290 verify(mExpandButton).setSummary(nullable(String.class)); 291 assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1); 292 293 // 3 prefs on screen, 2 are real and the last one is more button. 294 when(mScreen.getPreferenceCount()).thenReturn(3); 295 when(mScreen.getPreference(1)).thenReturn(lastPref); 296 297 final Preference toBeAdded = new Preference(mAppContext); 298 toBeAdded.setOrder(200); 299 mMixin.addPreference(mScreen, toBeAdded); 300 301 verify(mScreen, never()).removePreference(any(Preference.class)); 302 verify(mScreen, never()).addPreference(any(Preference.class)); 303 verify(mExpandButton, times(2)).setSummary(nullable(String.class)); 304 assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded); 305 } 306 307 @Test updateExpandSummary_noPref_noSummary()308 public void updateExpandSummary_noPref_noSummary() { 309 mMixin.updateExpandButtonSummary(); 310 311 verify(mExpandButton).setSummary(null); 312 } 313 314 @Test updateExpandSummary_doNotIncludeEmptyPrefTitle()315 public void updateExpandSummary_doNotIncludeEmptyPrefTitle() { 316 final Preference pref1 = new Preference(mAppContext); 317 pref1.setTitle("1"); 318 final Preference pref2 = new Preference(mAppContext); 319 pref2.setTitle(null); 320 final Preference pref3 = new Preference(mAppContext); 321 pref3.setTitle("3"); 322 final Preference pref4 = new Preference(mAppContext); 323 pref4.setTitle(""); 324 325 mMixin.addToCollapsedList(pref1); 326 mMixin.addToCollapsedList(pref2); 327 mMixin.addToCollapsedList(pref3); 328 mMixin.addToCollapsedList(pref4); 329 330 verify(mExpandButton).setSummary("1, 3"); 331 } 332 333 @Test updateExapndSummary_singlePref_expandSummarySameAsPrefTitle()334 public void updateExapndSummary_singlePref_expandSummarySameAsPrefTitle() { 335 final String TEST = "test"; 336 final Preference pref = new Preference(mAppContext); 337 pref.setTitle(TEST); 338 339 mMixin.addToCollapsedList(pref); 340 verify(mExpandButton).setSummary(TEST); 341 } 342 343 @Test updateExapndSummary_multiPrefs_useCombinedPrefTitleAsSummary()344 public void updateExapndSummary_multiPrefs_useCombinedPrefTitleAsSummary() { 345 final String TEST1 = "test1"; 346 final String TEST2 = "test2"; 347 final Preference pref1 = new Preference(mAppContext); 348 pref1.setTitle(TEST1); 349 final Preference pref2 = new Preference(mAppContext); 350 pref2.setTitle(TEST2); 351 352 mMixin.addToCollapsedList(pref1); 353 mMixin.addToCollapsedList(pref2); 354 355 verify(mExpandButton) 356 .setSummary(mAppContext.getString(R.string.join_many_items_middle, TEST1, TEST2)); 357 } 358 } 359