From 7bd7f0d15345d44481db0d3c29787ef29f6b62dd Mon Sep 17 00:00:00 2001 From: Steve McKay Date: Fri, 27 Apr 2018 14:24:25 -0700 Subject: Guard against NPEs in pre-init selection helper. Some input events may arrive in such an order that DocsSelectionHelper gets called before it's `reset` method. In those cases we're seeing an NPE. BUG: 69306667 Test: Added new basic. Change-Id: I0e6c73861a7cd7b3d65512e2822b7854622e11ab --- .../android/documentsui/DocsSelectionHelper.java | 100 ++++++++++++++++++++- .../documentsui/DocsSelectionHelperTest.java | 9 ++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/com/android/documentsui/DocsSelectionHelper.java b/src/com/android/documentsui/DocsSelectionHelper.java index 2c6b63b83..ebdfc9b3a 100644 --- a/src/com/android/documentsui/DocsSelectionHelper.java +++ b/src/com/android/documentsui/DocsSelectionHelper.java @@ -21,6 +21,7 @@ import android.support.v7.widget.RecyclerView; import com.android.documentsui.selection.DefaultSelectionHelper; import com.android.documentsui.selection.DefaultSelectionHelper.SelectionMode; +import com.android.documentsui.selection.MutableSelection; import com.android.documentsui.selection.Selection; import com.android.documentsui.selection.SelectionHelper; @@ -37,7 +38,10 @@ public final class DocsSelectionHelper extends SelectionHelper { private final DelegateFactory mFactory; private final @SelectionMode int mSelectionMode; - private @Nullable SelectionHelper mDelegate; + // initialize to a dummy object incase we get some input + // event drive calls before we're properly initialized. + // See: b/69306667. + private SelectionHelper mDelegate = new DummySelectionHelper(); @VisibleForTesting DocsSelectionHelper(DelegateFactory factory, @SelectionMode int mode) { @@ -188,4 +192,98 @@ public final class DocsSelectionHelper extends SelectionHelper { return new DefaultSelectionHelper(mode, adapter, stableIds, canSetState); } } + + /** + * A dummy SelectHelper used by DocsSelectionHelper before a real + * SelectionHelper has been initialized by DirectoryFragment. + */ + private static final class DummySelectionHelper extends SelectionHelper { + + @Override + public void addObserver(SelectionObserver listener) { + } + + @Override + public boolean hasSelection() { + return false; + } + + @Override + public Selection getSelection() { + return new MutableSelection(); + } + + @Override + public void copySelection(Selection dest) { + } + + @Override + public boolean isSelected(String id) { + return false; + } + + @VisibleForTesting + public void replaceSelection(Iterable ids) { + } + + @Override + public void restoreSelection(Selection other) { + } + + @Override + public boolean setItemsSelected(Iterable ids, boolean selected) { + return false; + } + + @Override + public void clearSelection() { + } + + @Override + public boolean select(String modelId) { + return false; + } + + @Override + public boolean deselect(String modelId) { + return false; + } + + @Override + public void startRange(int pos) { + } + + @Override + public void extendRange(int pos) { + } + + @Override + public void extendProvisionalRange(int pos) { + } + + @Override + public void clearProvisionalSelection() { + } + + @Override + public void setProvisionalSelection(Set newSelection) { + } + + @Override + public void mergeProvisionalSelection() { + } + + @Override + public void endRange() { + } + + @Override + public boolean isRangeActive() { + return false; + } + + @Override + public void anchorRange(int position) { + } + } } diff --git a/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java index 845a5dadb..42f6bb05c 100644 --- a/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java +++ b/tests/unit/com/android/documentsui/DocsSelectionHelperTest.java @@ -17,6 +17,8 @@ package com.android.documentsui; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.support.test.filters.SmallTest; @@ -71,6 +73,13 @@ public class DocsSelectionHelperTest { mSelectionMgr = new DocsSelectionHelper(mFactory, DefaultSelectionHelper.MODE_MULTIPLE); } + @Test + public void testCallableBeforeReset() { + mSelectionMgr.hasSelection(); + assertNotNull(mSelectionMgr.getSelection()); + assertFalse(mSelectionMgr.isSelected("poodle")); + } + @Test public void testReset_CreatesNewInstances() { mSelectionMgr.reset(null, null, null); // nulls are passed to factory. We ignore. -- cgit v1.2.3-59-g8ed1b