Prevent crashes when swiping an unbound header.

Changing the behavior when an unbound HeaderViewHolder is swiped to be more defensive. Instead of throwing a NPE and crashing the app, the Header will be treated as a non-swipeable Header.

PiperOrigin-RevId: 247227135
Change-Id: I965bb09d29de54ec48f3da9c547b6ec2070d716f
diff --git a/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java b/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java
index 2864de3..6c13457 100644
--- a/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java
+++ b/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java
@@ -14,12 +14,12 @@
 
 package com.google.android.libraries.feed.basicstream.internal.viewholders;
 
-import static com.google.android.libraries.feed.common.Validators.checkNotNull;
 
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 import com.google.android.libraries.feed.api.stream.Header;
+import com.google.android.libraries.feed.common.logging.Logger;
 
 /** {@link FeedViewHolder} for headers. */
 public class HeaderViewHolder extends FeedViewHolder implements SwipeableViewHolder {
@@ -59,12 +59,24 @@
 
   @Override
   public boolean canSwipe() {
-    return checkNotNull(header, "canSwipe cannot be called before viewholder is bound.")
-        .isDismissible();
+    if (header == null) {
+      Logger.w(TAG, "canSwipe should not be called before viewholder is bound.");
+
+      // Instead of crashing if viewholder is not bound, disable swiping behavior.
+      return false;
+    }
+    return header.isDismissible();
   }
 
   @Override
   public void onSwiped() {
-    checkNotNull(swipeNotifier, "canSwipe cannot be called before viewholder is bound.").onSwiped();
+    if (swipeNotifier == null) {
+      Logger.w(TAG, "onSwiped should not be called before viewholder is bound.");
+
+      // Instead of crashing if viewholder is not bound, disable swiping behavior.
+      return;
+    }
+
+    swipeNotifier.onSwiped();
   }
 }
diff --git a/src/test/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolderTest.java b/src/test/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolderTest.java
index 5bd227f..36e5cda 100644
--- a/src/test/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolderTest.java
+++ b/src/test/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolderTest.java
@@ -15,6 +15,7 @@
 package com.google.android.libraries.feed.basicstream.internal.viewholders;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
@@ -84,6 +85,13 @@
   }
 
   @Test
+  public void testCanSwipe_returnsFalse_whenViewHolderNotBound() {
+    when(header.isDismissible()).thenReturn(true);
+
+    assertThat(headerViewHolder.canSwipe()).isFalse();
+  }
+
+  @Test
   public void testOnSwiped() {
     headerViewHolder.bind(header, swipeNotifier);
 
@@ -91,4 +99,11 @@
 
     verify(swipeNotifier).onSwiped();
   }
+
+  @Test
+  public void testOnSwiped_doesNotCallOnSwiped_whenViewHolderNotBound() {
+    headerViewHolder.onSwiped();
+
+    verify(swipeNotifier, never()).onSwiped();
+  }
 }