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.applications.manageapplications; 18 19 import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING; 20 import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; 21 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL; 22 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN; 23 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION; 24 import static com.google.common.truth.Truth.assertThat; 25 26 import static junit.framework.Assert.assertEquals; 27 28 import static org.mockito.ArgumentMatchers.anyBoolean; 29 import static org.mockito.Matchers.any; 30 import static org.mockito.Matchers.anyInt; 31 import static org.mockito.Matchers.eq; 32 import static org.mockito.Mockito.doNothing; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.spy; 36 import static org.mockito.Mockito.verify; 37 import static org.mockito.Mockito.when; 38 39 import android.app.Activity; 40 import android.content.Context; 41 import android.os.Bundle; 42 import android.os.Looper; 43 import android.os.UserManager; 44 import android.support.v7.widget.RecyclerView; 45 import android.view.LayoutInflater; 46 import android.view.Menu; 47 import android.view.MenuItem; 48 import android.view.View; 49 import android.view.ViewGroup; 50 51 import com.android.settings.R; 52 import com.android.settings.testutils.SettingsRobolectricTestRunner; 53 import com.android.settings.widget.LoadingViewController; 54 import com.android.settingslib.applications.ApplicationsState; 55 56 import org.junit.Before; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 import org.mockito.Mock; 60 import org.mockito.MockitoAnnotations; 61 import org.robolectric.RuntimeEnvironment; 62 import org.robolectric.fakes.RoboMenuItem; 63 import org.robolectric.util.ReflectionHelpers; 64 65 import java.util.ArrayList; 66 67 @RunWith(SettingsRobolectricTestRunner.class) 68 public class ManageApplicationsTest { 69 70 @Mock 71 private ApplicationsState mState; 72 @Mock 73 private ApplicationsState.Session mSession; 74 @Mock 75 private Menu mMenu; 76 private MenuItem mAppReset; 77 private MenuItem mSortRecent; 78 private MenuItem mSortFrequent; 79 private ManageApplications mFragment; 80 81 @Before 82 public void setUp() { 83 MockitoAnnotations.initMocks(this); 84 mAppReset = new RoboMenuItem(R.id.reset_app_preferences); 85 mSortRecent = new RoboMenuItem(R.id.sort_order_recent_notification); 86 mSortFrequent = new RoboMenuItem(R.id.sort_order_frequent_notification); 87 ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mState); 88 when(mState.newSession(any())).thenReturn(mSession); 89 when(mState.getBackgroundLooper()).thenReturn(Looper.myLooper()); 90 91 mFragment = new ManageApplications(); 92 } 93 94 @Test 95 public void updateMenu_mainListType_showAppReset() { 96 setUpOptionMenus(); 97 ReflectionHelpers.setField(mFragment, "mListType", LIST_TYPE_MAIN); 98 ReflectionHelpers.setField(mFragment, "mOptionsMenu", mMenu); 99 100 mFragment.updateOptionsMenu(); 101 assertThat(mMenu.findItem(R.id.reset_app_preferences).isVisible()).isTrue(); 102 } 103 104 @Test 105 public void updateMenu_batteryListType_hideAppReset() { 106 setUpOptionMenus(); 107 ReflectionHelpers.setField(mFragment, "mListType", ManageApplications.LIST_TYPE_HIGH_POWER); 108 ReflectionHelpers.setField(mFragment, "mOptionsMenu", mMenu); 109 110 mFragment.updateOptionsMenu(); 111 assertThat(mMenu.findItem(R.id.reset_app_preferences).isVisible()).isFalse(); 112 } 113 114 @Test 115 public void updateMenu_hideNotificationOptions() { 116 setUpOptionMenus(); 117 ReflectionHelpers.setField(mFragment, "mListType", LIST_TYPE_NOTIFICATION); 118 ReflectionHelpers.setField(mFragment, "mOptionsMenu", mMenu); 119 120 mFragment.updateOptionsMenu(); 121 assertThat(mMenu.findItem(R.id.sort_order_recent_notification).isVisible()).isFalse(); 122 assertThat(mMenu.findItem(R.id.sort_order_frequent_notification).isVisible()).isFalse(); 123 } 124 125 126 @Test 127 public void onCreateView_shouldNotShowLoadingContainer() { 128 final ManageApplications fragment = spy(new ManageApplications()); 129 ReflectionHelpers.setField(fragment, "mResetAppsHelper", 130 mock(ResetAppsHelper.class)); 131 doNothing().when(fragment).createHeader(); 132 133 final LayoutInflater layoutInflater = mock(LayoutInflater.class); 134 final View view = mock(View.class); 135 final View loadingContainer = mock(View.class); 136 when(layoutInflater.inflate(anyInt(), eq(null))).thenReturn(view); 137 when(view.findViewById(R.id.loading_container)).thenReturn(loadingContainer); 138 139 fragment.onCreateView(layoutInflater, mock(ViewGroup.class), null); 140 141 verify(loadingContainer, never()).setVisibility(View.VISIBLE); 142 } 143 144 @Test 145 public void updateLoading_appLoaded_shouldNotDelayCallToHandleLoadingContainer() { 146 final ManageApplications fragment = mock(ManageApplications.class); 147 ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); 148 ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); 149 when(fragment.getActivity()).thenReturn(mock(Activity.class)); 150 final ManageApplications.ApplicationsAdapter adapter = 151 spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 152 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle())); 153 final LoadingViewController loadingViewController = 154 mock(LoadingViewController.class); 155 ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController); 156 157 // app loading completed 158 ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); 159 final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); 160 appList.add(mock(ApplicationsState.AppEntry.class)); 161 when(mSession.getAllApps()).thenReturn(appList); 162 163 adapter.updateLoading(); 164 165 verify(loadingViewController, never()).showLoadingViewDelayed(); 166 } 167 168 @Test 169 public void updateLoading_appNotLoaded_shouldDelayCallToHandleLoadingContainer() { 170 final ManageApplications fragment = mock(ManageApplications.class); 171 ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); 172 ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); 173 when(fragment.getActivity()).thenReturn(mock(Activity.class)); 174 final ManageApplications.ApplicationsAdapter adapter = 175 spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 176 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle())); 177 final LoadingViewController loadingViewController = 178 mock(LoadingViewController.class); 179 ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController); 180 181 // app loading not yet completed 182 ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); 183 184 adapter.updateLoading(); 185 186 verify(loadingViewController).showLoadingViewDelayed(); 187 } 188 189 @Test 190 public void shouldUseStableItemHeight_mainType_yes() { 191 assertThat(ManageApplications.ApplicationsAdapter.shouldUseStableItemHeight( 192 LIST_TYPE_MAIN)) 193 .isTrue(); 194 assertThat(ManageApplications.ApplicationsAdapter.shouldUseStableItemHeight( 195 LIST_TYPE_NOTIFICATION)) 196 .isFalse(); 197 } 198 199 @Test 200 public void onRebuildComplete_shouldHideLoadingView() { 201 final Context context = RuntimeEnvironment.application; 202 final ManageApplications fragment = mock(ManageApplications.class); 203 final RecyclerView recyclerView = mock(RecyclerView.class); 204 final View emptyView = mock(View.class); 205 ReflectionHelpers.setField(fragment, "mRecyclerView", recyclerView); 206 ReflectionHelpers.setField(fragment, "mEmptyView", emptyView); 207 final View loadingContainer = mock(View.class); 208 when(loadingContainer.getContext()).thenReturn(context); 209 final View listContainer = mock(View.class); 210 when(listContainer.getVisibility()).thenReturn(View.INVISIBLE); 211 when(listContainer.getContext()).thenReturn(context); 212 ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer); 213 ReflectionHelpers.setField(fragment, "mListContainer", listContainer); 214 when(fragment.getActivity()).thenReturn(mock(Activity.class)); 215 final ManageApplications.ApplicationsAdapter adapter = 216 spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 217 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle())); 218 final LoadingViewController loadingViewController = 219 mock(LoadingViewController.class); 220 ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController); 221 ReflectionHelpers.setField(adapter, "mAppFilter", 222 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)); 223 224 // app loading not yet completed 225 ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); 226 adapter.updateLoading(); 227 228 // app loading completed 229 ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); 230 final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); 231 appList.add(mock(ApplicationsState.AppEntry.class)); 232 when(mSession.getAllApps()).thenReturn(appList); 233 234 adapter.onRebuildComplete(null); 235 236 verify(loadingViewController).showContent(true /* animate */); 237 } 238 239 @Test 240 public void notifyItemChange_recyclerViewIdle_shouldNotify() { 241 final RecyclerView recyclerView = mock(RecyclerView.class); 242 final ManageApplications.ApplicationsAdapter adapter = 243 spy(new ManageApplications.ApplicationsAdapter(mState, 244 mock(ManageApplications.class), 245 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle())); 246 247 adapter.onAttachedToRecyclerView(recyclerView); 248 adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_IDLE); 249 adapter.mOnScrollListener.postNotifyItemChange(0 /* index */); 250 251 verify(adapter).notifyItemChanged(0); 252 } 253 254 @Test 255 public void notifyItemChange_recyclerViewScrolling_shouldNotifyWhenIdle() { 256 final RecyclerView recyclerView = mock(RecyclerView.class); 257 final ManageApplications.ApplicationsAdapter adapter = 258 spy(new ManageApplications.ApplicationsAdapter(mState, 259 mock(ManageApplications.class), 260 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle())); 261 262 adapter.onAttachedToRecyclerView(recyclerView); 263 adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_DRAGGING); 264 adapter.mOnScrollListener.postNotifyItemChange(0 /* index */); 265 266 verify(adapter, never()).notifyItemChanged(0); 267 verify(adapter, never()).notifyDataSetChanged(); 268 269 adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_IDLE); 270 verify(adapter).notifyDataSetChanged(); 271 } 272 273 @Test 274 public void applicationsAdapter_onBindViewHolder_updateSwitch_notifications() { 275 ManageApplications manageApplications = mock(ManageApplications.class); 276 when(manageApplications.getActivity()).thenReturn(mock(Activity.class)); 277 UserManager um = mock(UserManager.class); 278 when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); 279 ReflectionHelpers.setField(manageApplications, "mUserManager", um); 280 manageApplications.mListType = LIST_TYPE_NOTIFICATION; 281 ApplicationViewHolder holder = mock(ApplicationViewHolder.class); 282 ReflectionHelpers.setField(holder, "itemView", mock(View.class)); 283 ManageApplications.ApplicationsAdapter adapter = 284 new ManageApplications.ApplicationsAdapter(mState, 285 manageApplications, mock(AppFilterItem.class), 286 mock(Bundle.class)); 287 final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); 288 appList.add(mock(ApplicationsState.AppEntry.class)); 289 ReflectionHelpers.setField(adapter, "mEntries", appList); 290 291 adapter.onBindViewHolder(holder, 0); 292 verify(holder).updateSwitch(any(), anyBoolean(), anyBoolean()); 293 } 294 295 @Test 296 public void applicationsAdapter_onBindViewHolder_updateSwitch_notNotifications() { 297 ManageApplications manageApplications = mock(ManageApplications.class); 298 manageApplications.mListType = LIST_TYPE_MAIN; 299 ApplicationViewHolder holder = mock(ApplicationViewHolder.class); 300 ReflectionHelpers.setField(holder, "itemView", mock(View.class)); 301 UserManager um = mock(UserManager.class); 302 when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); 303 ReflectionHelpers.setField(manageApplications, "mUserManager", um); 304 ManageApplications.ApplicationsAdapter adapter = 305 new ManageApplications.ApplicationsAdapter(mState, 306 manageApplications, mock(AppFilterItem.class), 307 mock(Bundle.class)); 308 final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); 309 appList.add(mock(ApplicationsState.AppEntry.class)); 310 ReflectionHelpers.setField(adapter, "mEntries", appList); 311 312 adapter.onBindViewHolder(holder, 0); 313 verify(holder, never()).updateSwitch(any(), anyBoolean(), anyBoolean()); 314 } 315 316 @Test 317 public void sortOrderSavedOnRebuild() { 318 ManageApplications manageApplications = mock(ManageApplications.class); 319 when(manageApplications.getActivity()).thenReturn(mock(Activity.class)); 320 UserManager um = mock(UserManager.class); 321 when(um.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); 322 ReflectionHelpers.setField(manageApplications, "mUserManager", um); 323 manageApplications.mListType = LIST_TYPE_NOTIFICATION; 324 manageApplications.mSortOrder = -1; 325 ManageApplications.ApplicationsAdapter adapter = 326 new ManageApplications.ApplicationsAdapter(mState, 327 manageApplications, mock(AppFilterItem.class), 328 mock(Bundle.class)); 329 330 adapter.rebuild(mSortRecent.getItemId()); 331 assertThat(manageApplications.mSortOrder).isEqualTo(mSortRecent.getItemId()); 332 333 adapter.rebuild(mSortFrequent.getItemId()); 334 assertThat(manageApplications.mSortOrder).isEqualTo(mSortFrequent.getItemId()); 335 } 336 337 private void setUpOptionMenus() { 338 when(mMenu.findItem(anyInt())).thenAnswer(invocation -> { 339 final Object[] args = invocation.getArguments(); 340 final int id = (int) args[0]; 341 if (id == mAppReset.getItemId()) { 342 return mAppReset; 343 } 344 if (id == mSortFrequent.getItemId()) { 345 return mSortFrequent; 346 } 347 if (id == mSortRecent.getItemId()) { 348 return mSortRecent; 349 } 350 return new RoboMenuItem(id); 351 }); 352 } 353 } 354