Loading src/com/android/settings/Utils.java +2 −0 Original line number Diff line number Diff line Loading @@ -943,6 +943,8 @@ public final class Utils extends com.android.settingslib.Utils { return result; } // TODO: move this out of Utils to a mixin or a controller or a helper class. @Deprecated public static void handleLoadingContainer(View loading, View doneLoading, boolean done, boolean animate) { setViewShown(loading, !done, animate); Loading src/com/android/settings/applications/ManageApplications.java +26 −6 Original line number Diff line number Diff line Loading @@ -346,7 +346,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment mRootView = inflater.inflate(R.layout.manage_applications_apps, null); mLoadingContainer = mRootView.findViewById(R.id.loading_container); mLoadingContainer.setVisibility(View.VISIBLE); mListContainer = mRootView.findViewById(R.id.list_container); if (mListContainer != null) { // Create adapter and list view here Loading Loading @@ -395,7 +394,8 @@ public class ManageApplications extends InstrumentedPreferenceFragment return mRootView; } private void createHeader() { @VisibleForTesting void createHeader() { Activity activity = getActivity(); FrameLayout pinnedHeader = (FrameLayout) mRootView.findViewById(R.id.pinned_header); mSpinnerHeader = activity.getLayoutInflater() Loading Loading @@ -834,6 +834,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment static class ApplicationsAdapter extends BaseAdapter implements Filterable, ApplicationsState.Callbacks, AppStateBaseBridge.Callback, AbsListView.RecyclerListener, SectionIndexer { // how long to wait for app list to populate without showing the loading container private static final long DELAY_SHOW_LOADING_CONTAINER_THRESHOLD_MS = 100L; private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0]; private final ApplicationsState mState; Loading Loading @@ -889,6 +893,13 @@ public class ManageApplications extends InstrumentedPreferenceFragment } }; private Runnable mShowLoadingContainerRunnable = new Runnable() { public void run() { Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, false /* done */, false /* animate */); } }; public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications, int filterMode) { mState = state; Loading Loading @@ -1097,6 +1108,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment if (mSession.getAllApps().size() != 0 && mManageApplications.mListContainer.getVisibility() != View.VISIBLE) { // Cancel any pending task to show the loading animation and show the list of // apps directly. mFgHandler.removeCallbacks(mShowLoadingContainerRunnable); Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, true, true); } Loading Loading @@ -1148,10 +1162,16 @@ public class ManageApplications extends InstrumentedPreferenceFragment } } private void updateLoading() { @VisibleForTesting void updateLoading() { final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0; if (appLoaded) { Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, mHasReceivedLoadEntries && mSession.getAllApps().size() != 0, false); mManageApplications.mListContainer, true /* done */, false /* animate */); } else { mFgHandler.postDelayed( mShowLoadingContainerRunnable, DELAY_SHOW_LOADING_CONTAINER_THRESHOLD_MS); } } ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix, Loading tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java +116 −1 Original line number Diff line number Diff line Loading @@ -17,29 +17,38 @@ package com.android.settings.applications; import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.SettingsShadowResources.SettingsShadowTheme; import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.fakes.RoboMenuItem; import org.robolectric.util.ReflectionHelpers; Loading @@ -47,7 +56,12 @@ import org.robolectric.util.ReflectionHelpers; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -132,6 +146,107 @@ public class ManageApplicationsTest { assertThat(mMenu.findItem(R.id.reset_app_preferences).isVisible()).isFalse(); } @Test public void onCreateView_shouldNotShowLoadingContainer() { final ManageApplications fragment = spy(new ManageApplications()); ReflectionHelpers.setField(fragment, "mResetAppsHelper", mock(ResetAppsHelper.class)); doNothing().when(fragment).createHeader(); final LayoutInflater layoutInflater = mock(LayoutInflater.class); final View view = mock(View.class); final View loadingContainer = mock(View.class); when(layoutInflater.inflate(anyInt(), eq(null))).thenReturn(view); when(view.findViewById(R.id.loading_container)).thenReturn(loadingContainer); fragment.onCreateView(layoutInflater, mock(ViewGroup.class), null); verify(loadingContainer, never()).setVisibility(View.VISIBLE); } @Test public void updateLoading_appLoaded_shouldNotDelayCallToHandleLoadingContainer() { final ManageApplications fragment = mock(ManageApplications.class); ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); // app loading completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); appList.add(mock(ApplicationsState.AppEntry.class)); when(mSession.getAllApps()).thenReturn(appList); adapter.updateLoading(); verify(handler, never()).postDelayed(eq(showLoadingContainerRunnable), anyLong()); } @Test public void updateLoading_appNotLoaded_shouldDelayCallToHandleLoadingContainer() { final ManageApplications fragment = mock(ManageApplications.class); ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); // app loading not yet completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); adapter.updateLoading(); verify(handler).postDelayed(eq(showLoadingContainerRunnable), anyLong()); } @Test public void onRebuildComplete_shouldCancelDelayedRunnable() { final Context context = RuntimeEnvironment.application; final ManageApplications fragment = mock(ManageApplications.class); final View loadingContainer = mock(View.class); when(loadingContainer.getContext()).thenReturn(context); final View listContainer = mock(View.class); when(listContainer.getVisibility()).thenReturn(View.INVISIBLE); when(listContainer.getContext()).thenReturn(context); ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer); ReflectionHelpers.setField(fragment, "mListContainer", listContainer); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); ReflectionHelpers.setField(adapter, "mFilterMode", -1); // app loading not yet completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); adapter.updateLoading(); // app loading completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); appList.add(mock(ApplicationsState.AppEntry.class)); when(mSession.getAllApps()).thenReturn(appList); adapter.onRebuildComplete(null); verify(handler).removeCallbacks(showLoadingContainerRunnable); } private void setUpOptionMenus() { when(mMenu.findItem(anyInt())).thenAnswer(invocation -> { final Object[] args = invocation.getArguments(); Loading Loading
src/com/android/settings/Utils.java +2 −0 Original line number Diff line number Diff line Loading @@ -943,6 +943,8 @@ public final class Utils extends com.android.settingslib.Utils { return result; } // TODO: move this out of Utils to a mixin or a controller or a helper class. @Deprecated public static void handleLoadingContainer(View loading, View doneLoading, boolean done, boolean animate) { setViewShown(loading, !done, animate); Loading
src/com/android/settings/applications/ManageApplications.java +26 −6 Original line number Diff line number Diff line Loading @@ -346,7 +346,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment mRootView = inflater.inflate(R.layout.manage_applications_apps, null); mLoadingContainer = mRootView.findViewById(R.id.loading_container); mLoadingContainer.setVisibility(View.VISIBLE); mListContainer = mRootView.findViewById(R.id.list_container); if (mListContainer != null) { // Create adapter and list view here Loading Loading @@ -395,7 +394,8 @@ public class ManageApplications extends InstrumentedPreferenceFragment return mRootView; } private void createHeader() { @VisibleForTesting void createHeader() { Activity activity = getActivity(); FrameLayout pinnedHeader = (FrameLayout) mRootView.findViewById(R.id.pinned_header); mSpinnerHeader = activity.getLayoutInflater() Loading Loading @@ -834,6 +834,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment static class ApplicationsAdapter extends BaseAdapter implements Filterable, ApplicationsState.Callbacks, AppStateBaseBridge.Callback, AbsListView.RecyclerListener, SectionIndexer { // how long to wait for app list to populate without showing the loading container private static final long DELAY_SHOW_LOADING_CONTAINER_THRESHOLD_MS = 100L; private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0]; private final ApplicationsState mState; Loading Loading @@ -889,6 +893,13 @@ public class ManageApplications extends InstrumentedPreferenceFragment } }; private Runnable mShowLoadingContainerRunnable = new Runnable() { public void run() { Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, false /* done */, false /* animate */); } }; public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications, int filterMode) { mState = state; Loading Loading @@ -1097,6 +1108,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment if (mSession.getAllApps().size() != 0 && mManageApplications.mListContainer.getVisibility() != View.VISIBLE) { // Cancel any pending task to show the loading animation and show the list of // apps directly. mFgHandler.removeCallbacks(mShowLoadingContainerRunnable); Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, true, true); } Loading Loading @@ -1148,10 +1162,16 @@ public class ManageApplications extends InstrumentedPreferenceFragment } } private void updateLoading() { @VisibleForTesting void updateLoading() { final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0; if (appLoaded) { Utils.handleLoadingContainer(mManageApplications.mLoadingContainer, mManageApplications.mListContainer, mHasReceivedLoadEntries && mSession.getAllApps().size() != 0, false); mManageApplications.mListContainer, true /* done */, false /* animate */); } else { mFgHandler.postDelayed( mShowLoadingContainerRunnable, DELAY_SHOW_LOADING_CONTAINER_THRESHOLD_MS); } } ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix, Loading
tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java +116 −1 Original line number Diff line number Diff line Loading @@ -17,29 +17,38 @@ package com.android.settings.applications; import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.SettingsShadowResources.SettingsShadowTheme; import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.fakes.RoboMenuItem; import org.robolectric.util.ReflectionHelpers; Loading @@ -47,7 +56,12 @@ import org.robolectric.util.ReflectionHelpers; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -132,6 +146,107 @@ public class ManageApplicationsTest { assertThat(mMenu.findItem(R.id.reset_app_preferences).isVisible()).isFalse(); } @Test public void onCreateView_shouldNotShowLoadingContainer() { final ManageApplications fragment = spy(new ManageApplications()); ReflectionHelpers.setField(fragment, "mResetAppsHelper", mock(ResetAppsHelper.class)); doNothing().when(fragment).createHeader(); final LayoutInflater layoutInflater = mock(LayoutInflater.class); final View view = mock(View.class); final View loadingContainer = mock(View.class); when(layoutInflater.inflate(anyInt(), eq(null))).thenReturn(view); when(view.findViewById(R.id.loading_container)).thenReturn(loadingContainer); fragment.onCreateView(layoutInflater, mock(ViewGroup.class), null); verify(loadingContainer, never()).setVisibility(View.VISIBLE); } @Test public void updateLoading_appLoaded_shouldNotDelayCallToHandleLoadingContainer() { final ManageApplications fragment = mock(ManageApplications.class); ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); // app loading completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); appList.add(mock(ApplicationsState.AppEntry.class)); when(mSession.getAllApps()).thenReturn(appList); adapter.updateLoading(); verify(handler, never()).postDelayed(eq(showLoadingContainerRunnable), anyLong()); } @Test public void updateLoading_appNotLoaded_shouldDelayCallToHandleLoadingContainer() { final ManageApplications fragment = mock(ManageApplications.class); ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class)); ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class)); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); // app loading not yet completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); adapter.updateLoading(); verify(handler).postDelayed(eq(showLoadingContainerRunnable), anyLong()); } @Test public void onRebuildComplete_shouldCancelDelayedRunnable() { final Context context = RuntimeEnvironment.application; final ManageApplications fragment = mock(ManageApplications.class); final View loadingContainer = mock(View.class); when(loadingContainer.getContext()).thenReturn(context); final View listContainer = mock(View.class); when(listContainer.getVisibility()).thenReturn(View.INVISIBLE); when(listContainer.getContext()).thenReturn(context); ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer); ReflectionHelpers.setField(fragment, "mListContainer", listContainer); when(fragment.getActivity()).thenReturn(mock(Activity.class)); final Runnable showLoadingContainerRunnable = mock(Runnable.class); final Handler handler = mock(Handler.class); final ManageApplications.ApplicationsAdapter adapter = spy(new ManageApplications.ApplicationsAdapter(mState, fragment, 0)); ReflectionHelpers.setField(adapter, "mShowLoadingContainerRunnable", showLoadingContainerRunnable); ReflectionHelpers.setField(adapter, "mFgHandler", handler); ReflectionHelpers.setField(adapter, "mFilterMode", -1); // app loading not yet completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false); adapter.updateLoading(); // app loading completed ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true); final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>(); appList.add(mock(ApplicationsState.AppEntry.class)); when(mSession.getAllApps()).thenReturn(appList); adapter.onRebuildComplete(null); verify(handler).removeCallbacks(showLoadingContainerRunnable); } private void setUpOptionMenus() { when(mMenu.findItem(anyInt())).thenAnswer(invocation -> { final Object[] args = invocation.getArguments(); Loading