Loading src/com/android/settings/homepage/contextualcards/ContextualCard.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } } Loading src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java +7 −4 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading tests/robotests/src/com/android/settings/homepage/contextualcards/EligibleCardCheckerTest.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -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") Loading tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +38 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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)); Loading Loading @@ -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(); } } } } Loading
src/com/android/settings/homepage/contextualcards/ContextualCard.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } } Loading
src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java +7 −4 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading
src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading
tests/robotests/src/com/android/settings/homepage/contextualcards/EligibleCardCheckerTest.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -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") Loading
tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +38 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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)); Loading Loading @@ -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(); } } } }