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