Merge "Fix the janky transition of contextual cards." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ff35a3e641
@@ -23,6 +23,7 @@ import android.net.Uri;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.LayoutRes;
|
import androidx.annotation.LayoutRes;
|
||||||
|
import androidx.slice.Slice;
|
||||||
|
|
||||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
|
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ public class ContextualCard {
|
|||||||
private final int mViewType;
|
private final int mViewType;
|
||||||
private final boolean mIsPendingDismiss;
|
private final boolean mIsPendingDismiss;
|
||||||
private final boolean mHasInlineAction;
|
private final boolean mHasInlineAction;
|
||||||
|
private final Slice mSlice;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return mName;
|
return mName;
|
||||||
@@ -127,6 +129,10 @@ public class ContextualCard {
|
|||||||
return mHasInlineAction;
|
return mHasInlineAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Slice getSlice() {
|
||||||
|
return mSlice;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder mutate() {
|
public Builder mutate() {
|
||||||
return mBuilder;
|
return mBuilder;
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,7 @@ public class ContextualCard {
|
|||||||
mViewType = builder.mViewType;
|
mViewType = builder.mViewType;
|
||||||
mIsPendingDismiss = builder.mIsPendingDismiss;
|
mIsPendingDismiss = builder.mIsPendingDismiss;
|
||||||
mHasInlineAction = builder.mHasInlineAction;
|
mHasInlineAction = builder.mHasInlineAction;
|
||||||
|
mSlice = builder.mSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextualCard(Cursor c) {
|
ContextualCard(Cursor c) {
|
||||||
@@ -179,6 +186,8 @@ public class ContextualCard {
|
|||||||
mBuilder.setIsPendingDismiss(mIsPendingDismiss);
|
mBuilder.setIsPendingDismiss(mIsPendingDismiss);
|
||||||
mHasInlineAction = false;
|
mHasInlineAction = false;
|
||||||
mBuilder.setHasInlineAction(mHasInlineAction);
|
mBuilder.setHasInlineAction(mHasInlineAction);
|
||||||
|
mSlice = null;
|
||||||
|
mBuilder.setSlice(mSlice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -225,6 +234,7 @@ public class ContextualCard {
|
|||||||
private int mViewType;
|
private int mViewType;
|
||||||
private boolean mIsPendingDismiss;
|
private boolean mIsPendingDismiss;
|
||||||
private boolean mHasInlineAction;
|
private boolean mHasInlineAction;
|
||||||
|
private Slice mSlice;
|
||||||
|
|
||||||
public Builder setName(String name) {
|
public Builder setName(String name) {
|
||||||
mName = name;
|
mName = name;
|
||||||
@@ -296,6 +306,14 @@ public class ContextualCard {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache a slice created at pre-check time for later usage.
|
||||||
|
*/
|
||||||
|
public Builder setSlice(Slice slice) {
|
||||||
|
mSlice = slice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ContextualCard build() {
|
public ContextualCard build() {
|
||||||
return new ContextualCard(this);
|
return new ContextualCard(this);
|
||||||
}
|
}
|
||||||
|
@@ -96,14 +96,17 @@ public class EligibleCardChecker implements Callable<ContextualCard> {
|
|||||||
|
|
||||||
final Slice slice = bindSlice(uri);
|
final Slice slice = bindSlice(uri);
|
||||||
|
|
||||||
if (isSliceToggleable(slice)) {
|
|
||||||
mCard = card.mutate().setHasInlineAction(true).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slice == null || slice.hasHint(HINT_ERROR)) {
|
if (slice == null || slice.hasHint(HINT_ERROR)) {
|
||||||
Log.w(TAG, "Failed to bind slice, not eligible for display " + uri);
|
Log.w(TAG, "Failed to bind slice, not eligible for display " + uri);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mCard = card.mutate().setSlice(slice).build();
|
||||||
|
|
||||||
|
if (isSliceToggleable(slice)) {
|
||||||
|
mCard = card.mutate().setHasInlineAction(true).build();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,6 +47,7 @@ import com.android.settings.homepage.contextualcards.CardContentProvider;
|
|||||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||||
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
|
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
|
||||||
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
||||||
|
import com.android.settings.homepage.contextualcards.slices.SliceFullCardRendererHelper.SliceViewHolder;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -102,6 +103,11 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show cached slice first before slice binding completed to avoid jank.
|
||||||
|
if (holder.getItemViewType() != VIEW_TYPE_HALF_WIDTH) {
|
||||||
|
((SliceViewHolder) holder).sliceView.setSlice(card.getSlice());
|
||||||
|
}
|
||||||
|
|
||||||
LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
|
LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
|
||||||
|
|
||||||
if (sliceLiveData == null) {
|
if (sliceLiveData == null) {
|
||||||
|
@@ -114,6 +114,17 @@ public class EligibleCardCheckerTest {
|
|||||||
.isFalse();
|
.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) {
|
private ContextualCard getContextualCard(Uri sliceUri) {
|
||||||
return new ContextualCard.Builder()
|
return new ContextualCard.Builder()
|
||||||
.setName("test_card")
|
.setName("test_card")
|
||||||
|
@@ -17,10 +17,12 @@
|
|||||||
package com.android.settings.homepage.contextualcards.slices;
|
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_FULL_WIDTH;
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_STICKY;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.app.Activity;
|
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.ContextualCard;
|
||||||
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
||||||
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
|
||||||
|
import com.android.settings.wifi.slice.ContextualWifiSlice;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -81,7 +84,7 @@ public class SliceContextualCardRendererTest {
|
|||||||
@Test
|
@Test
|
||||||
public void bindView_invalidScheme_sliceShouldBeNull() {
|
public void bindView_invalidScheme_sliceShouldBeNull() {
|
||||||
final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
|
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));
|
mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
|
||||||
|
|
||||||
@@ -90,6 +93,29 @@ public class SliceContextualCardRendererTest {
|
|||||||
.isNull();
|
.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
|
@Test
|
||||||
public void bindView_newSliceLiveData_shouldAddDataToMap() {
|
public void bindView_newSliceLiveData_shouldAddDataToMap() {
|
||||||
mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
|
mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
|
||||||
@@ -246,12 +272,23 @@ public class SliceContextualCardRendererTest {
|
|||||||
return mRenderer.createViewHolder(view, VIEW_TYPE_FULL_WIDTH);
|
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) {
|
private ContextualCard buildContextualCard(Uri sliceUri) {
|
||||||
|
final Slice slice = new ContextualWifiSlice(mActivity).getSlice();
|
||||||
return new ContextualCard.Builder()
|
return new ContextualCard.Builder()
|
||||||
.setName("test_name")
|
.setName("test_name")
|
||||||
.setCardType(ContextualCard.CardType.SLICE)
|
.setCardType(ContextualCard.CardType.SLICE)
|
||||||
.setSliceUri(sliceUri)
|
.setSliceUri(sliceUri)
|
||||||
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
.setViewType(VIEW_TYPE_FULL_WIDTH)
|
||||||
|
.setSlice(slice)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user