Hack to wait for both suggestion/category to load
- This is unfortunately necessary to avoid a jank when category load completes before suggestion load, in which case user has to manually scroll up to see the suggestions. - We could technically just add scrollTo(0), but that causes the list scroll on its own within 0.5 second of settings start, and that's bad. Change-Id: I8dc869a69a5bf11bbf7644b281cc1778dd1a90e8 Fixes: 69068691 Test: visual Test: robotests
This commit is contained in:
@@ -161,7 +161,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSuggestionsV2(List<Suggestion> data) {
|
public void setSuggestionsV2(List<Suggestion> data) {
|
||||||
// TODO: Tint icon
|
|
||||||
final DashboardData prevData = mDashboardData;
|
final DashboardData prevData = mDashboardData;
|
||||||
mDashboardData = new DashboardData.Builder(prevData)
|
mDashboardData = new DashboardData.Builder(prevData)
|
||||||
.setSuggestionsV2(data)
|
.setSuggestionsV2(data)
|
||||||
|
@@ -81,6 +81,9 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
private boolean isOnCategoriesChangedCalled;
|
private boolean isOnCategoriesChangedCalled;
|
||||||
private boolean mOnConditionsChangedCalled;
|
private boolean mOnConditionsChangedCalled;
|
||||||
|
|
||||||
|
private DashboardCategory mStagingCategory;
|
||||||
|
private List<Suggestion> mStagingSuggestions;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.DASHBOARD_SUMMARY;
|
return MetricsEvent.DASHBOARD_SUMMARY;
|
||||||
@@ -291,7 +294,13 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuggestionReady(List<Suggestion> suggestions) {
|
public void onSuggestionReady(List<Suggestion> suggestions) {
|
||||||
|
mStagingSuggestions = suggestions;
|
||||||
mAdapter.setSuggestionsV2(suggestions);
|
mAdapter.setSuggestionsV2(suggestions);
|
||||||
|
if (mStagingCategory != null) {
|
||||||
|
Log.d(TAG, "Category has loaded, setting category from suggestionReady");
|
||||||
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
|
mAdapter.setCategory(mStagingCategory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -342,7 +351,19 @@ public class DashboardSummary extends InstrumentedFragment
|
|||||||
final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
|
final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
|
||||||
CategoryKey.CATEGORY_HOMEPAGE);
|
CategoryKey.CATEGORY_HOMEPAGE);
|
||||||
mSummaryLoader.updateSummaryToCache(category);
|
mSummaryLoader.updateSummaryToCache(category);
|
||||||
ThreadUtils.postOnMainThread(() -> mAdapter.setCategory(category));
|
mStagingCategory = category;
|
||||||
|
if (mSuggestionControllerMixin.isSuggestionLoaded()) {
|
||||||
|
Log.d(TAG, "Suggestion has loaded, setting suggestion/category");
|
||||||
|
ThreadUtils.postOnMainThread(() -> {
|
||||||
|
if (mStagingSuggestions != null) {
|
||||||
|
mAdapter.setSuggestionsV2(mStagingSuggestions);
|
||||||
|
}
|
||||||
|
mAdapter.setCategory(mStagingCategory);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Suggestion NOT loaded, delaying setCategory by " + MAX_WAIT_MILLIS + "ms");
|
||||||
|
mHandler.postDelayed(() -> mAdapter.setCategory(mStagingCategory), MAX_WAIT_MILLIS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -59,6 +59,8 @@ public class SuggestionControllerMixin implements SuggestionController.ServiceCo
|
|||||||
private final SuggestionController mSuggestionController;
|
private final SuggestionController mSuggestionController;
|
||||||
private final SuggestionControllerHost mHost;
|
private final SuggestionControllerHost mHost;
|
||||||
|
|
||||||
|
private boolean mSuggestionLoaded;
|
||||||
|
|
||||||
public SuggestionControllerMixin(Context context, SuggestionControllerHost host,
|
public SuggestionControllerMixin(Context context, SuggestionControllerHost host,
|
||||||
Lifecycle lifecycle) {
|
Lifecycle lifecycle) {
|
||||||
mContext = context.getApplicationContext();
|
mContext = context.getApplicationContext();
|
||||||
@@ -106,6 +108,7 @@ public class SuggestionControllerMixin implements SuggestionController.ServiceCo
|
|||||||
@Override
|
@Override
|
||||||
public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) {
|
public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) {
|
||||||
if (id == SuggestionLoader.LOADER_ID_SUGGESTIONS) {
|
if (id == SuggestionLoader.LOADER_ID_SUGGESTIONS) {
|
||||||
|
mSuggestionLoaded = false;
|
||||||
return new SuggestionLoader(mContext, mSuggestionController);
|
return new SuggestionLoader(mContext, mSuggestionController);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("This loader id is not supported " + id);
|
throw new IllegalArgumentException("This loader id is not supported " + id);
|
||||||
@@ -113,12 +116,17 @@ public class SuggestionControllerMixin implements SuggestionController.ServiceCo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<List<Suggestion>> loader, List<Suggestion> data) {
|
public void onLoadFinished(Loader<List<Suggestion>> loader, List<Suggestion> data) {
|
||||||
|
mSuggestionLoaded = true;
|
||||||
mHost.onSuggestionReady(data);
|
mHost.onSuggestionReady(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(Loader<List<Suggestion>> loader) {
|
public void onLoaderReset(Loader<List<Suggestion>> loader) {
|
||||||
|
mSuggestionLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuggestionLoaded() {
|
||||||
|
return mSuggestionLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dismissSuggestion(Suggestion suggestion) {
|
public void dismissSuggestion(Suggestion suggestion) {
|
||||||
|
@@ -18,9 +18,7 @@ package com.android.settings.dashboard.suggestions;
|
|||||||
|
|
||||||
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
|
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
|
||||||
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
|
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -37,9 +35,9 @@ import org.junit.After;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@@ -49,19 +47,18 @@ import org.robolectric.annotation.Config;
|
|||||||
})
|
})
|
||||||
public class SuggestionControllerMixinTest {
|
public class SuggestionControllerMixinTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
|
||||||
private Context mContext;
|
|
||||||
@Mock
|
@Mock
|
||||||
private SuggestionControllerMixin.SuggestionControllerHost mHost;
|
private SuggestionControllerMixin.SuggestionControllerHost mHost;
|
||||||
|
private Context mContext;
|
||||||
private Lifecycle mLifecycle;
|
private Lifecycle mLifecycle;
|
||||||
private SuggestionControllerMixin mMixin;
|
private SuggestionControllerMixin mMixin;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
FakeFeatureFactory.setupForTest(mContext);
|
mContext = RuntimeEnvironment.application;
|
||||||
|
FakeFeatureFactory.setupForTest();
|
||||||
mLifecycle = new Lifecycle(() -> mLifecycle);
|
mLifecycle = new Lifecycle(() -> mLifecycle);
|
||||||
when(mContext.getApplicationContext()).thenReturn(mContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -111,4 +108,17 @@ public class SuggestionControllerMixinTest {
|
|||||||
|
|
||||||
verify(mHost).getLoaderManager();
|
verify(mHost).getLoaderManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doneLoadingg_shouldSetSuggestionLoaded() {
|
||||||
|
mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle);
|
||||||
|
|
||||||
|
mMixin.onLoadFinished(mock(SuggestionLoader.class), null);
|
||||||
|
|
||||||
|
assertThat(mMixin.isSuggestionLoaded()).isTrue();
|
||||||
|
|
||||||
|
mMixin.onLoaderReset(mock(SuggestionLoader.class));
|
||||||
|
|
||||||
|
assertThat(mMixin.isSuggestionLoaded()).isFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user