Fix the janky transition of contextual cards.

When contextual cards are being laid out, there are two separate layout
transitions, which brings users the feeling of slowness.

In the current design, we bind slices in the adapter's
onBindViewHolder(), where slice's binding is acutally done in the
background thread and it's time consuming. So before getting the
callback from the slice framework to have actual contents, the view is
empty but the viewholder is already created. So the RecyclerView would
treat it as completed and starts to lay them out. This introduces the
first time transition. Once we get the actual slice content, the view
will be refreshed and laid out, which is the second time transition.

To tackle this, this CL caches slices that are created at pre-check
time, and use them to render before getting updated slices to fill up
the gap.

Fixes: 156372414
Test: robotest and launch settings to see the transition being smooth.
Change-Id: Ic0a27ff36f1824de499b75ec73b2635de9cbe6b5
This commit is contained in:
Yi-Ling Chuang
2020-05-29 18:10:03 +08:00
parent fb6711ae92
commit bed0f23940
5 changed files with 80 additions and 5 deletions

View File

@@ -114,6 +114,17 @@ public class EligibleCardCheckerTest {
.isFalse();
}
@Test
public void isCardEligibleToDisplay_sliceNotNull_cacheSliceToCard() {
final ContextualWifiSlice wifiSlice = new ContextualWifiSlice(mContext);
final Slice slice = wifiSlice.getSlice();
doReturn(slice).when(mEligibleCardChecker).bindSlice(any(Uri.class));
mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI));
assertThat(mEligibleCardChecker.mCard.getSlice()).isNotNull();
}
private ContextualCard getContextualCard(Uri sliceUri) {
return new ContextualCard.Builder()
.setName("test_card")

View File

@@ -17,10 +17,12 @@
package com.android.settings.homepage.contextualcards.slices;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_STICKY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.Activity;
@@ -39,6 +41,7 @@ import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
import com.android.settings.wifi.slice.ContextualWifiSlice;
import org.junit.Before;
import org.junit.Test;
@@ -81,7 +84,7 @@ public class SliceContextualCardRendererTest {
@Test
public void bindView_invalidScheme_sliceShouldBeNull() {
final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
@@ -90,6 +93,29 @@ public class SliceContextualCardRendererTest {
.isNull();
}
@Test
public void bindView_viewTypeFullWidth_shouldSetCachedSlice() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
assertThat(
((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView.getSlice())
.isNotNull();
}
@Test
public void bindView_viewTypeSticky_shouldSetCachedSlice() {
final RecyclerView.ViewHolder viewHolder = spy(getStickyViewHolder());
doReturn(VIEW_TYPE_STICKY).when(viewHolder).getItemViewType();
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
assertThat(
((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView.getSlice())
.isNotNull();
}
@Test
public void bindView_newSliceLiveData_shouldAddDataToMap() {
mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
@@ -246,12 +272,23 @@ public class SliceContextualCardRendererTest {
return mRenderer.createViewHolder(view, VIEW_TYPE_FULL_WIDTH);
}
private RecyclerView.ViewHolder getStickyViewHolder() {
final RecyclerView recyclerView = new RecyclerView(mActivity);
recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
final View view = LayoutInflater.from(mActivity).inflate(VIEW_TYPE_STICKY, recyclerView,
false);
return mRenderer.createViewHolder(view, VIEW_TYPE_STICKY);
}
private ContextualCard buildContextualCard(Uri sliceUri) {
final Slice slice = new ContextualWifiSlice(mActivity).getSlice();
return new ContextualCard.Builder()
.setName("test_name")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(sliceUri)
.setViewType(VIEW_TYPE_FULL_WIDTH)
.setSlice(slice)
.build();
}
}