release-request-276f9f52-87fd-4915-bd79-9a2f0ee77433-for-git_oc-release-4090213 snap-temp-L31600000073091223

Change-Id: I000970b5f49fa4d8b7d33342ede87ea55042a579
diff --git a/Android.mk b/Android.mk
index 57b1ac7..99545dc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -54,6 +54,22 @@
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 #-------------------------------
+# build a host test jar
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
+LOCAL_JAVA_RESOURCE_DIRS := src/test/resources
+LOCAL_MODULE := junit-params-test-host
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	junit-params-host \
+	junit-params-assertj-core-host
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+#-------------------------------
 # build a target test jar
 #
 # Run the test jar as follows:
@@ -83,3 +99,14 @@
     junit-params-assertj-core:lib/assertj-core-1.7.1.jar
 
 include $(BUILD_MULTI_PREBUILT)
+
+#-------------------------------
+# prebuilt dependencies
+
+include $(CLEAR_VARS)
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+    junit-params-assertj-core-host:lib/assertj-core-1.7.1.jar
+
+include $(BUILD_MULTI_PREBUILT)
diff --git a/README.google b/README.google
index 3f85ec8..47541ba 100644
--- a/README.google
+++ b/README.google
@@ -14,3 +14,7 @@
                  java.beans.PropertyEditorManager classes by
                  removing the usages of them.
       36074730 - Make sure that filters affect the Description.
+      36541809 - Hard code the description name to be compatible with CTS
+                 and prevent use of @TestCaseName.
+                 Ignore tests broken by the above change.
+      38419944 - Fix sharding on CTS.
diff --git a/src/main/java/junitparams/JUnitParamsRunner.java b/src/main/java/junitparams/JUnitParamsRunner.java
index 970529e..edd0ad4 100644
--- a/src/main/java/junitparams/JUnitParamsRunner.java
+++ b/src/main/java/junitparams/JUnitParamsRunner.java
@@ -1,19 +1,20 @@
 package junitparams;
 
-import java.util.ArrayList;
 import java.util.List;
 
+import junitparams.internal.MethodBlockSupplier;
 import org.junit.runner.Description;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.NoTestsRemainException;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runners.BlockJUnit4ClassRunner;
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.Statement;
 
-import junitparams.internal.ParameterisedTestClassRunner;
-import junitparams.internal.ParametrizedTestMethodsFilter;
+import junitparams.internal.DescribableFrameworkMethod;
+import junitparams.internal.InstanceFrameworkMethod;
+import junitparams.internal.InvokableFrameworkMethod;
+import junitparams.internal.NonParameterisedFrameworkMethod;
+import junitparams.internal.ParameterisedFrameworkMethod;
 import junitparams.internal.TestMethod;
 
 /**
@@ -385,22 +386,16 @@
  */
 public class JUnitParamsRunner extends BlockJUnit4ClassRunner {
 
-    private ParametrizedTestMethodsFilter parametrizedTestMethodsFilter = new ParametrizedTestMethodsFilter(this);
-    private ParameterisedTestClassRunner parameterisedRunner;
-    private Description description;
+    private final MethodBlockSupplier methodBlockSupplier;
 
     public JUnitParamsRunner(Class<?> klass) throws InitializationError {
         super(klass);
-        parameterisedRunner = new ParameterisedTestClassRunner(getTestClass());
-    }
-
-    @Override
-    public void filter(Filter filter) throws NoTestsRemainException {
-        super.filter(filter);
-        // Android-changed: Applying a filter could change the description so invalidate any cached
-        // description. See b/36074730
-        description = null;
-        this.parametrizedTestMethodsFilter = new ParametrizedTestMethodsFilter(this,filter);
+        methodBlockSupplier = new MethodBlockSupplier() {
+            @Override
+            public Statement getMethodBlock(InvokableFrameworkMethod method) {
+                return methodBlock(method);
+            }
+        };
     }
 
     @Override
@@ -412,74 +407,76 @@
 
     @Override
     protected void runChild(FrameworkMethod method, RunNotifier notifier) {
-        if (handleIgnored(method, notifier))
+        DescribableFrameworkMethod describableMethod = getDescribableMethod(method);
+        if (handleIgnored(describableMethod, notifier))
             return;
 
-        TestMethod testMethod = parameterisedRunner.testMethodFor(method);
-        if (parameterisedRunner.shouldRun(testMethod)){
-            parameterisedRunner.runParameterisedTest(testMethod, methodBlock(method), notifier);
+        if (method instanceof ParameterisedFrameworkMethod) {
+            ParameterisedFrameworkMethod parameterisedFrameworkMethod =
+                    (ParameterisedFrameworkMethod) method;
+
+            List<InstanceFrameworkMethod> methods = parameterisedFrameworkMethod.getMethods();
+            for (InstanceFrameworkMethod frameworkMethod : methods) {
+                frameworkMethod.run(methodBlockSupplier, notifier);
+            }
         }
-        else{
-            verifyMethodCanBeRunByStandardRunner(testMethod);
-            super.runChild(method, notifier);
+        else if (describableMethod instanceof InvokableFrameworkMethod) {
+            ((InvokableFrameworkMethod) describableMethod).run(methodBlockSupplier, notifier);
+        }
+        else {
+            throw new IllegalStateException(
+                    "Unsupported FrameworkMethod class: " + method.getClass());
         }
     }
 
-    private void verifyMethodCanBeRunByStandardRunner(TestMethod testMethod) {
-        List<Throwable> errors = new ArrayList<Throwable>();
-        testMethod.frameworkMethod().validatePublicVoidNoArg(false, errors);
-        if (!errors.isEmpty()) {
-            throw new RuntimeException(errors.get(0));
+    /**
+     * Check that the supplied method is one that was originally in the list returned by
+     * {@link #computeTestMethods()}.
+     *
+     * @param method the method, must be an instance of {@link DescribableFrameworkMethod}
+     * @return the supplied method cast to {@link DescribableFrameworkMethod}
+     * @throws IllegalArgumentException if the supplied method is not a
+     *         {@link DescribableFrameworkMethod}
+     */
+    private DescribableFrameworkMethod getDescribableMethod(FrameworkMethod method) {
+        if (!(method instanceof DescribableFrameworkMethod)) {
+            throw new IllegalArgumentException(
+                    "Unsupported FrameworkMethod class: " + method.getClass()
+                            + ", expected a DescribableFrameworkMethod subclass");
         }
+
+        return (DescribableFrameworkMethod) method;
     }
 
-    private boolean handleIgnored(FrameworkMethod method, RunNotifier notifier) {
-        TestMethod testMethod = parameterisedRunner.testMethodFor(method);
-        if (testMethod.isIgnored())
-            notifier.fireTestIgnored(describeMethod(method));
+    private boolean handleIgnored(DescribableFrameworkMethod method, RunNotifier notifier) {
+        // A parameterised method that is ignored (either due to @Ignore or due to empty parameters)
+        // is treated as if it was a non-parameterised method.
+        boolean ignored = (method instanceof NonParameterisedFrameworkMethod)
+                && ((NonParameterisedFrameworkMethod) method).isIgnored();
+        if (ignored)
+            notifier.fireTestIgnored(method.getDescription());
 
-        return testMethod.isIgnored();
+        return ignored;
     }
 
     @Override
     protected List<FrameworkMethod> computeTestMethods() {
-        return parameterisedRunner.computeFrameworkMethods();
+        return TestMethod.listFrom(getTestClass());
     }
 
     @Override
     protected Statement methodInvoker(FrameworkMethod method, Object test) {
-        Statement methodInvoker = parameterisedRunner.parameterisedMethodInvoker(method, test);
-        if (methodInvoker == null)
-            methodInvoker = super.methodInvoker(method, test);
-
-        return methodInvoker;
+        if (method instanceof InvokableFrameworkMethod) {
+            return ((InvokableFrameworkMethod) method).getInvokeStatement(test);
+        }
+        throw new IllegalStateException(
+                "Unsupported FrameworkMethod class: " + method.getClass()
+                        + ", expected an InvokableFrameworkMethod subclass");
     }
 
     @Override
-    public Description getDescription() {
-        if (description == null) {
-            description = Description.createSuiteDescription(getName(), getTestClass().getAnnotations());
-            List<FrameworkMethod> resultMethods = getListOfMethods();
-
-            for (FrameworkMethod method : resultMethods)
-                description.addChild(describeMethod(method));
-        }
-
-        return description;
-    }
-
-    private List<FrameworkMethod> getListOfMethods() {
-        List<FrameworkMethod> frameworkMethods = parameterisedRunner.returnListOfMethods();
-        return parametrizedTestMethodsFilter.filteredMethods(frameworkMethods);
-    }
-
-    public Description describeMethod(FrameworkMethod method) {
-        Description child = parameterisedRunner.describeParameterisedMethod(method);
-
-        if (child == null)
-            child = describeChild(method);
-
-        return child;
+    protected Description describeChild(FrameworkMethod method) {
+        return getDescribableMethod(method).getDescription();
     }
 
     /**
diff --git a/src/main/java/junitparams/internal/DeferredErrorFrameworkMethod.java b/src/main/java/junitparams/internal/DeferredErrorFrameworkMethod.java
new file mode 100644
index 0000000..b6e843e
--- /dev/null
+++ b/src/main/java/junitparams/internal/DeferredErrorFrameworkMethod.java
@@ -0,0 +1,39 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.Statement;
+
+/**
+ * Encapsulates a {@link Throwable} that was caught during initialization so that it can be
+ * thrown during execution in order to preserve previous behavior.
+ */
+public class DeferredErrorFrameworkMethod extends InvokableFrameworkMethod {
+
+    private final Throwable throwable;
+
+    DeferredErrorFrameworkMethod(Method method, Description description,
+            Throwable throwable) {
+        super(method, description);
+        this.throwable = throwable;
+    }
+
+    @Override
+    public Statement getInvokeStatement(Object test) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                throw throwable;
+            }
+        };
+    }
+
+    @Override
+    public void run(MethodBlockSupplier supplier, RunNotifier notifier) {
+        // Do not call the MethodBlockSupplier as that could introduce additional errors, simply
+        // throw the encapsulated Throwable immediately.
+        runMethodInvoker(notifier, getInvokeStatement(notifier), getDescription());
+    }
+}
diff --git a/src/main/java/junitparams/internal/DescribableFrameworkMethod.java b/src/main/java/junitparams/internal/DescribableFrameworkMethod.java
new file mode 100644
index 0000000..c529292
--- /dev/null
+++ b/src/main/java/junitparams/internal/DescribableFrameworkMethod.java
@@ -0,0 +1,17 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+
+import org.junit.runner.Describable;
+import org.junit.runner.Description;
+import org.junit.runners.model.FrameworkMethod;
+
+/**
+ * A {@link FrameworkMethod} that also provides a {@link Description}.
+ */
+public abstract class DescribableFrameworkMethod extends FrameworkMethod implements Describable {
+
+    DescribableFrameworkMethod(Method method) {
+        super(method);
+    }
+}
diff --git a/src/main/java/junitparams/internal/InstanceFrameworkMethod.java b/src/main/java/junitparams/internal/InstanceFrameworkMethod.java
new file mode 100644
index 0000000..ad70454
--- /dev/null
+++ b/src/main/java/junitparams/internal/InstanceFrameworkMethod.java
@@ -0,0 +1,57 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * A {@link FrameworkMethod} that represents an instance of an 
+ * {@link ParameterisedFrameworkMethod}, that is the combination of the test method with the
+ * parameter set that it will be passed.
+ */
+public class InstanceFrameworkMethod extends InvokableFrameworkMethod {
+
+    private final Description instanceDescription;
+
+    private final Object parametersSet;
+
+    /**
+     * Create an {@link InstanceFrameworkMethod}.
+     *
+     * <p>It has two {@link Description} instances because it has to provide different
+     * {@link Description} to {@link TestRule} instances than other usages in order to maintain
+     * backwards compatibility.
+     *
+     * @param method the test method
+     * @param description the description that is supplied to {@link TestRule} instances.
+     * @param instanceDescription the description used for all other purposes, e.g. filtering,
+     *         {@link Runner#getDescription()} and {@link RunListener}.
+     * @param parametersSet the set of parameters to pass to the method.
+     */
+    InstanceFrameworkMethod(Method method, Description description,
+            Description instanceDescription, Object parametersSet) {
+        super(method, description);
+        this.instanceDescription = instanceDescription;
+        this.parametersSet = parametersSet;
+    }
+
+    @Override
+    public Statement getInvokeStatement(Object test) {
+        return new InvokeParameterisedMethod(this, test, parametersSet);
+    }
+
+    Description getInstanceDescription() {
+        return instanceDescription;
+    }
+
+    @Override
+    public void run(MethodBlockSupplier supplier, RunNotifier notifier) {
+        runMethodInvoker(notifier, supplier.getMethodBlock(this), getInstanceDescription());
+    }
+}
diff --git a/src/main/java/junitparams/internal/InvokableFrameworkMethod.java b/src/main/java/junitparams/internal/InvokableFrameworkMethod.java
new file mode 100644
index 0000000..0ed0bdb
--- /dev/null
+++ b/src/main/java/junitparams/internal/InvokableFrameworkMethod.java
@@ -0,0 +1,59 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+import junitparams.JUnitParamsRunner;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * Base for {@link FrameworkMethod} classes that provide a {@link Statement} for invoking.
+ */
+public abstract class InvokableFrameworkMethod extends DescribableFrameworkMethod {
+
+    private final Description description;
+
+    InvokableFrameworkMethod(Method method, Description description) {
+        super(method);
+        this.description = description;
+    }
+
+    @Override
+    public Description getDescription() {
+        return description;
+    }
+
+    /**
+     * Create a {@link Statement} that when called will invoke the method.
+     *
+     * <p>This is usually called from the
+     * {@link JUnitParamsRunner#methodInvoker(FrameworkMethod, Object)} method via the
+     * {@link MethodBlockSupplier} which is usually called from within the
+     * {@link #run(MethodBlockSupplier, RunNotifier)} method.
+     *
+     * @param test
+     *         the object on which the method will be invoked.
+     * @return the {@link Statement}.
+     */
+    public abstract Statement getInvokeStatement(Object test);
+
+    void runMethodInvoker(RunNotifier notifier, Statement methodInvoker,
+            Description methodWithParams) {
+        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, methodWithParams);
+        eachNotifier.fireTestStarted();
+        try {
+            methodInvoker.evaluate();
+        } catch (AssumptionViolatedException e) {
+            eachNotifier.addFailedAssumption(e);
+        } catch (Throwable e) {
+            eachNotifier.addFailure(e);
+        } finally {
+            eachNotifier.fireTestFinished();
+        }
+    }
+
+    public abstract void run(MethodBlockSupplier supplier, RunNotifier notifier);
+}
diff --git a/src/main/java/junitparams/internal/InvokeNonParameterisedMethod.java b/src/main/java/junitparams/internal/InvokeNonParameterisedMethod.java
new file mode 100644
index 0000000..a4256a2
--- /dev/null
+++ b/src/main/java/junitparams/internal/InvokeNonParameterisedMethod.java
@@ -0,0 +1,24 @@
+package junitparams.internal;
+
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit invoker for non-parameterised test methods
+ */
+public class InvokeNonParameterisedMethod extends Statement {
+
+    private final FrameworkMethod testMethod;
+    private final Object testClass;
+
+    InvokeNonParameterisedMethod(FrameworkMethod testMethod, Object testClass) {
+        this.testMethod = testMethod;
+        this.testClass = testClass;
+    }
+
+    @Override
+    public void evaluate() throws Throwable {
+        testMethod.invokeExplosively(testClass);
+    }
+
+}
diff --git a/src/main/java/junitparams/internal/InvokeParameterisedMethod.java b/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
index 7d313c2..089bbe1 100644
--- a/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
+++ b/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
@@ -4,7 +4,6 @@
 import java.lang.reflect.Array;
 import java.math.BigDecimal;
 
-import org.junit.runner.Description;
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.Statement;
 
@@ -23,12 +22,10 @@
     private final Object[] params;
     private final FrameworkMethod testMethod;
     private final Object testClass;
-    private final String uniqueMethodId;
 
-    public InvokeParameterisedMethod(FrameworkMethod testMethod, Object testClass, Object params, int paramSetIdx) {
+    public InvokeParameterisedMethod(FrameworkMethod testMethod, Object testClass, Object params) {
         this.testMethod = testMethod;
         this.testClass = testClass;
-        this.uniqueMethodId = Utils.uniqueMethodId(paramSetIdx - 1, params, testMethod.getName());
         try {
             if (params instanceof String)
                 this.params = castParamsFromString((String) params);
@@ -218,10 +215,6 @@
                             + testMethod.getName() + " method.");
     }
 
-    boolean matchesDescription(Description description) {
-        return description.hashCode() == uniqueMethodId.hashCode();
-    }
-
     @Override
     public void evaluate() throws Throwable {
         testMethod.invokeExplosively(testClass, params == null ? new Object[]{params} : params);
diff --git a/src/main/java/junitparams/internal/MethodBlockSupplier.java b/src/main/java/junitparams/internal/MethodBlockSupplier.java
new file mode 100644
index 0000000..ce14955
--- /dev/null
+++ b/src/main/java/junitparams/internal/MethodBlockSupplier.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package junitparams.internal;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * Wraps the {@link Statement} provided by
+ * {@link InvokableFrameworkMethod#getInvokeStatement(Object)} with additional {@link Statement}.
+ *
+ * <p>This is essentially a method reference to
+ * {@link BlockJUnit4ClassRunner#methodBlock(FrameworkMethod)}
+ */
+public interface MethodBlockSupplier {
+
+    Statement getMethodBlock(InvokableFrameworkMethod method);
+}
diff --git a/src/main/java/junitparams/internal/NonParameterisedFrameworkMethod.java b/src/main/java/junitparams/internal/NonParameterisedFrameworkMethod.java
new file mode 100644
index 0000000..0e2d297
--- /dev/null
+++ b/src/main/java/junitparams/internal/NonParameterisedFrameworkMethod.java
@@ -0,0 +1,45 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+
+import org.junit.Ignore;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+/**
+ * A {@link FrameworkMethod} that represents an unparameterized method.
+ */
+public class NonParameterisedFrameworkMethod
+        extends InvokableFrameworkMethod {
+
+    private final boolean ignored;
+
+    /**
+     * Create a non-parameterised method.
+     *
+     * @param method the test method
+     * @param description the description of the method
+     * @param ignored true if the method should be ignore, either because the method has the
+     *     {@link Ignore} annotation, or because it is parameterised but is given no parameters.
+     */
+    NonParameterisedFrameworkMethod(Method method, Description description, boolean ignored) {
+        super(method, description);
+        this.ignored = ignored;
+    }
+
+    @Override
+    public Statement getInvokeStatement(Object test) {
+        return new InvokeNonParameterisedMethod(this, test);
+    }
+
+    @Override
+    public void run(MethodBlockSupplier supplier, RunNotifier notifier) {
+        runMethodInvoker(notifier, supplier.getMethodBlock(this), getDescription());
+    }
+
+    public boolean isIgnored() {
+        return ignored;
+    }
+}
diff --git a/src/main/java/junitparams/internal/ParameterisedFrameworkMethod.java b/src/main/java/junitparams/internal/ParameterisedFrameworkMethod.java
new file mode 100644
index 0000000..f593f4f
--- /dev/null
+++ b/src/main/java/junitparams/internal/ParameterisedFrameworkMethod.java
@@ -0,0 +1,85 @@
+package junitparams.internal;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runners.model.FrameworkMethod;
+
+/**
+ * A {@link FrameworkMethod} that represents a parameterized method.
+ *
+ * <p>This contains a list of {@link InstanceFrameworkMethod} that represent the individual
+ * instances of this method, one per parameter set.
+ */
+public class ParameterisedFrameworkMethod extends DescribableFrameworkMethod implements Filterable {
+
+    /**
+     * The base description, used as a template when creating {@link Description}.
+     */
+    private final Description baseDescription;
+
+    /**
+     * The list of {@link InstanceFrameworkMethod} that represent individual instances of this
+     * method.
+     */
+    private List<InstanceFrameworkMethod> instanceMethods;
+
+    /**
+     * The {@link Description}, created lazily and updated after filtering.
+     */
+    private Description description;
+
+    public ParameterisedFrameworkMethod(Method method, Description baseDescription,
+            List<InstanceFrameworkMethod> instanceMethods) {
+        super(method);
+        this.baseDescription = baseDescription;
+        this.instanceMethods = instanceMethods;
+    }
+
+    @Override
+    public Description getDescription() {
+        if (description == null) {
+            description = baseDescription.childlessCopy();
+            for (InstanceFrameworkMethod instanceMethod : instanceMethods) {
+                description.addChild(instanceMethod.getInstanceDescription());
+            }
+        }
+
+        return description;
+    }
+
+    public List<InstanceFrameworkMethod> getMethods() {
+        return instanceMethods;
+    }
+
+    @Override
+    public void filter(Filter filter) throws NoTestsRemainException {
+        int count = instanceMethods.size();
+        for (Iterator<InstanceFrameworkMethod> i = instanceMethods.iterator(); i.hasNext(); ) {
+            InstanceFrameworkMethod instanceMethod = i.next();
+            if (filter.shouldRun(instanceMethod.getInstanceDescription())) {
+                try {
+                    filter.apply(instanceMethod);
+                } catch (NoTestsRemainException e) {
+                    i.remove();
+                }
+            } else {
+                i.remove();
+            }
+        }
+
+        if (instanceMethods.size() != count) {
+            // Some instance methods have been filtered out, so invalidate the description.
+            description = null;
+        }
+
+        if (instanceMethods.isEmpty()) {
+            throw new NoTestsRemainException();
+        }
+    }
+}
diff --git a/src/main/java/junitparams/internal/ParameterisedTestClassRunner.java b/src/main/java/junitparams/internal/ParameterisedTestClassRunner.java
deleted file mode 100644
index 23daf88..0000000
--- a/src/main/java/junitparams/internal/ParameterisedTestClassRunner.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package junitparams.internal;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
-import org.junit.runners.model.TestClass;
-
-/**
- * Testclass-level functionalities to handle parameters from a JUnit runner
- * class.
- *
- * @author Pawel Lipinski
- */
-public class ParameterisedTestClassRunner {
-
-    protected Map<TestMethod, ParameterisedTestMethodRunner> parameterisedMethods = new HashMap<TestMethod, ParameterisedTestMethodRunner>();
-    protected Map<FrameworkMethod, TestMethod> testMethods = new HashMap<FrameworkMethod, TestMethod>();
-    protected List<TestMethod> testMethodsList;
-
-    /**
-     * Creates a runner for a given test class. Computes all the test methods
-     * that are annotated as tests. Retrieves and caches all parameter values.
-     *
-     * @param testClass
-     */
-    public ParameterisedTestClassRunner(TestClass testClass) {
-        computeTestMethods(testClass);
-        fillTestMethodsMap();
-        computeFrameworkMethods();
-    }
-
-    protected void computeTestMethods(TestClass testClass) {
-        testMethodsList = TestMethod.listFrom(testClass.getAnnotatedMethods(Test.class), testClass);
-    }
-
-    private void fillTestMethodsMap() {
-        for (TestMethod testMethod : testMethodsList)
-            testMethods.put(testMethod.frameworkMethod(), testMethod);
-    }
-
-    /**
-     * Returns a list of <code>FrameworkMethod</code>s. Handles both
-     * parameterised methods (counts them as many times as many paramsets they
-     * have) and nonparameterised methods (just counts them once).
-     *
-     * @return a list of FrameworkMethod objects
-     */
-    public List<FrameworkMethod> computeFrameworkMethods() {
-        List<FrameworkMethod> resultMethods = new ArrayList<FrameworkMethod>();
-
-        for (TestMethod testMethod : testMethodsList) {
-            if (testMethod.isParameterised())
-                addTestMethodForEachParamSet(resultMethods, testMethod);
-            else
-                addTestMethodOnce(resultMethods, testMethod);
-        }
-
-        return resultMethods;
-    }
-
-    /**
-     * Returns a list of <code>FrameworkMethod</code>s - once per method, like
-     * there were no parameters.
-     * For JUnit to build names for IDE.
-     */
-    public List<FrameworkMethod> returnListOfMethods() {
-        List<FrameworkMethod> resultMethods = new ArrayList<FrameworkMethod>();
-
-        for (TestMethod testMethod : testMethodsList) {
-            addTestMethodOnce(resultMethods, testMethod);
-            cacheMethodRunner(testMethod);
-            testMethod.warnIfNoParamsGiven();
-        }
-
-        return resultMethods;
-    }
-
-    private void addTestMethodForEachParamSet(List<FrameworkMethod> resultMethods, TestMethod testMethod) {
-        if (testMethod.isNotIgnored()) {
-            int paramSetSize = testMethod.parametersSets().length;
-            for (int i = 0; i < paramSetSize; i++)
-                addTestMethodOnce(resultMethods, testMethod);
-        } else {
-            addTestMethodOnce(resultMethods, testMethod);
-        }
-    }
-
-    private void addTestMethodOnce(List<FrameworkMethod> resultMethods, TestMethod testMethod) {
-        resultMethods.add(testMethod.frameworkMethod());
-    }
-
-    private void cacheMethodRunner(TestMethod testMethod) {
-        if (!parameterisedMethods.containsKey(testMethod))
-            parameterisedMethods.put(testMethod, new ParameterisedTestMethodRunner(testMethod));
-    }
-
-    /**
-     * Returns a InvokeParameterisedMethod for parameterised methods and null
-     * for nonparameterised
-     *
-     * @param method    Test method
-     * @param testClass
-     * @return a Statement with the invoker for the parameterised method
-     */
-    public Statement parameterisedMethodInvoker(FrameworkMethod method, Object testClass) {
-        TestMethod testMethod = testMethods.get(method);
-
-        if (!testMethod.isParameterised())
-            return null;
-
-        return buildMethodInvoker(method, testClass, testMethod);
-    }
-
-    private Statement buildMethodInvoker(FrameworkMethod method, Object testClass, TestMethod testMethod) {
-        ParameterisedTestMethodRunner parameterisedMethod = parameterisedMethods.get(testMethod);
-
-        return new InvokeParameterisedMethod(
-                method, testClass, parameterisedMethod.currentParamsFromAnnotation(), parameterisedMethod.count());
-    }
-
-    /**
-     * Tells if method should be run by this runner.
-     *
-     * @param testMethod
-     * @return true, iff testMethod should be run by this runner.
-     */
-    public boolean shouldRun(TestMethod testMethod) {
-        return testMethod.isParameterised();
-    }
-
-    /**
-     * Executes parameterised method.
-     *
-     * @param method
-     * @param methodInvoker
-     * @param notifier
-     */
-    public void runParameterisedTest(TestMethod method, Statement methodInvoker, RunNotifier notifier) {
-        parameterisedMethods.get(method).runTestMethod(methodInvoker, notifier);
-    }
-
-    /**
-     * Returns description of a parameterised method.
-     *
-     * @param method TODO
-     * @return Description of a method or null if it's not parameterised.
-     */
-    public Description describeParameterisedMethod(FrameworkMethod method) {
-        TestMethod testMethod = testMethods.get(method);
-
-        if (!testMethod.isParameterised())
-            return null;
-
-        return testMethod.describe();
-    }
-
-    /**
-     * Returns a cached TestMethod object related to the given FrameworkMethod.
-     * This object has all the params already retrieved, so use this one and not
-     * TestMethod's constructor if you want to have everything retrieved once
-     * and cached.
-     *
-     * @param method
-     * @return a cached TestMethod instance
-     */
-    public TestMethod testMethodFor(FrameworkMethod method) {
-        return testMethods.get(method);
-    }
-
-}
diff --git a/src/main/java/junitparams/internal/ParameterisedTestMethodRunner.java b/src/main/java/junitparams/internal/ParameterisedTestMethodRunner.java
deleted file mode 100644
index 9573048..0000000
--- a/src/main/java/junitparams/internal/ParameterisedTestMethodRunner.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package junitparams.internal;
-
-import java.lang.reflect.Field;
-
-import org.junit.internal.AssumptionViolatedException;
-import org.junit.internal.runners.model.EachTestNotifier;
-import org.junit.runner.Description;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.Statement;
-
-/**
- * Testmethod-level functionalities for parameterised tests
- *
- * @author Pawel Lipinski
- */
-public class ParameterisedTestMethodRunner {
-
-    public final TestMethod method;
-    private int count;
-
-    public ParameterisedTestMethodRunner(TestMethod testMethod) {
-        this.method = testMethod;
-    }
-
-    public int nextCount() {
-        return count++;
-    }
-
-    public int count() {
-        return count;
-    }
-
-    Object currentParamsFromAnnotation() {
-        return method.parametersSets()[nextCount()];
-    }
-
-    void runTestMethod(Statement methodInvoker, RunNotifier notifier) {
-        Description methodWithParams = findChildForParams(methodInvoker, method.describe());
-
-        runMethodInvoker(notifier, methodInvoker, methodWithParams);
-    }
-
-    private void runMethodInvoker(RunNotifier notifier, Statement methodInvoker, Description methodWithParams) {
-        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, methodWithParams);
-        eachNotifier.fireTestStarted();
-        try {
-            methodInvoker.evaluate();
-        } catch (AssumptionViolatedException e) {
-            eachNotifier.addFailedAssumption(e);
-        } catch (Throwable e) {
-            eachNotifier.addFailure(e);
-        } finally {
-            eachNotifier.fireTestFinished();
-        }
-    }
-
-    private Description findChildForParams(Statement methodInvoker, Description methodDescription) {
-        if (System.getProperty("JUnitParams.flat") != null)
-            return methodDescription;
-
-        InvokeParameterisedMethod parameterisedInvoker = findParameterisedMethodInvokerInChain(methodInvoker);
-
-        for (Description child : methodDescription.getChildren()) {
-            if (parameterisedInvoker.matchesDescription(child))
-                return child;
-        }
-        return null;
-    }
-
-    private InvokeParameterisedMethod findParameterisedMethodInvokerInChain(Statement methodInvoker) {
-        while (methodInvoker != null && !(methodInvoker instanceof InvokeParameterisedMethod))
-            methodInvoker = nextChainedInvoker(methodInvoker);
-
-        if (methodInvoker == null)
-            throw new RuntimeException("Cannot find invoker for the parameterised method. Using wrong JUnit version?");
-
-        return (InvokeParameterisedMethod) methodInvoker;
-    }
-
-    private Statement nextChainedInvoker(Statement methodInvoker) {
-        Field[] declaredFields = methodInvoker.getClass().getDeclaredFields();
-
-        for (Field field : declaredFields) {
-            Statement statement = statementOrNull(methodInvoker, field);
-            if (statement != null)
-                return statement;
-        }
-
-        return null;
-    }
-
-    private Statement statementOrNull(Statement methodInvoker, Field field) {
-        if (Statement.class.isAssignableFrom(field.getType()))
-            return getOriginalStatement(methodInvoker, field);
-
-        return null;
-    }
-
-    private Statement getOriginalStatement(Statement methodInvoker, Field field) {
-        field.setAccessible(true);
-        try {
-            return (Statement) field.get(methodInvoker);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-}
diff --git a/src/main/java/junitparams/internal/ParametrizedTestMethodsFilter.java b/src/main/java/junitparams/internal/ParametrizedTestMethodsFilter.java
deleted file mode 100644
index 905934c..0000000
--- a/src/main/java/junitparams/internal/ParametrizedTestMethodsFilter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package junitparams.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.runner.manipulation.Filter;
-import org.junit.runners.model.FrameworkMethod;
-
-import junitparams.JUnitParamsRunner;
-
-public class ParametrizedTestMethodsFilter {
-    private final junitparams.JUnitParamsRunner jUnitParamsRunner;
-
-    private final Filter filter;
-
-    public ParametrizedTestMethodsFilter(junitparams.JUnitParamsRunner jUnitParamsRunner, Filter filter) {
-        this.jUnitParamsRunner = jUnitParamsRunner;
-        this.filter = filter;
-    }
-
-    public ParametrizedTestMethodsFilter(JUnitParamsRunner jUnitParamsRunner) {
-        this.jUnitParamsRunner = jUnitParamsRunner;
-        this.filter = Filter.ALL;
-    }
-
-    public List<FrameworkMethod> filteredMethods(List<FrameworkMethod> frameworkMethods) {
-        List<FrameworkMethod> filteredMethods = new ArrayList<FrameworkMethod>();
-
-        for (FrameworkMethod frameworkMethod : frameworkMethods) {
-            if (filter.shouldRun(jUnitParamsRunner.describeMethod(frameworkMethod))) {
-                filteredMethods.add(frameworkMethod);
-            }
-        }
-
-        return filteredMethods;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/junitparams/internal/TestMethod.java b/src/main/java/junitparams/internal/TestMethod.java
index 6125803..d0188ef 100644
--- a/src/main/java/junitparams/internal/TestMethod.java
+++ b/src/main/java/junitparams/internal/TestMethod.java
@@ -1,11 +1,13 @@
 package junitparams.internal;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 import org.junit.Ignore;
+import org.junit.Test;
 import org.junit.runner.Description;
 import org.junit.runners.model.FrameworkMethod;
 import org.junit.runners.model.TestClass;
@@ -22,11 +24,12 @@
  */
 public class TestMethod {
     private FrameworkMethod frameworkMethod;
-    FrameworkMethodAnnotations frameworkMethodAnnotations;
+    private FrameworkMethodAnnotations frameworkMethodAnnotations;
     private Class<?> testClass;
     private ParametersReader parametersReader;
     private Object[] cachedParameters;
     private TestCaseNamingStrategy namingStrategy;
+    private DescribableFrameworkMethod describableFrameworkMethod;
 
     public TestMethod(FrameworkMethod method, TestClass testClass) {
         this.frameworkMethod = method;
@@ -41,11 +44,13 @@
         return frameworkMethod.getName();
     }
 
-    public static List<TestMethod> listFrom(List<FrameworkMethod> annotatedMethods, TestClass testClass) {
-        List<TestMethod> methods = new ArrayList<TestMethod>();
+    public static List<FrameworkMethod> listFrom(TestClass testClass) {
+        List<FrameworkMethod> methods = new ArrayList<FrameworkMethod>();
 
-        for (FrameworkMethod frameworkMethod : annotatedMethods)
-            methods.add(new TestMethod(frameworkMethod, testClass));
+        for (FrameworkMethod frameworkMethod : testClass.getAnnotatedMethods(Test.class)) {
+            TestMethod testMethod = new TestMethod(frameworkMethod, testClass);
+            methods.add(testMethod.describableFrameworkMethod());
+        }
 
         return methods;
     }
@@ -72,11 +77,11 @@
         return Arrays.equals(frameworkMethodParameterTypes, testMethodParameterTypes);
     }
 
-    Class<?> testClass() {
+    private Class<?> testClass() {
         return testClass;
     }
 
-    public boolean isIgnored() {
+    private boolean isIgnored() {
         return hasIgnoredAnnotation() || hasNoParameters();
     }
 
@@ -88,7 +93,7 @@
        return isParameterised() && parametersSets().length == 0;
     }
 
-    public boolean isNotIgnored() {
+    private boolean isNotIgnored() {
         return !isIgnored();
     }
 
@@ -96,27 +101,64 @@
         return frameworkMethodAnnotations.getAnnotation(annotationType);
     }
 
-    Description describe() {
-        if (isNotIgnored() && !describeFlat()) {
-            Description parametrised = Description.createSuiteDescription(name());
-            Object[] params = parametersSets();
-            for (int i = 0; i < params.length; i++) {
-                Object paramSet = params[i];
-                String name = namingStrategy.getTestCaseName(i, paramSet);
-                String uniqueMethodId = Utils.uniqueMethodId(i, paramSet, name());
+    private Description getDescription(Object[] params, int i) {
+        Object paramSet = params[i];
+        String name = namingStrategy.getTestCaseName(i, paramSet);
+        String uniqueMethodId = Utils.uniqueMethodId(i, paramSet, name());
 
-                parametrised.addChild(
-                        Description.createTestDescription(testClass().getName(), name, uniqueMethodId)
-                );
-            }
-            return parametrised;
-        } else {
-            return Description.createTestDescription(testClass(), name(), frameworkMethodAnnotations.allAnnotations());
-        }
+        return Description.createTestDescription(testClass().getName(), name, uniqueMethodId);
     }
 
-    private boolean describeFlat() {
-        return System.getProperty("JUnitParams.flat") != null;
+    DescribableFrameworkMethod describableFrameworkMethod() {
+        if (describableFrameworkMethod == null) {
+            Description baseDescription = Description.createTestDescription(
+                    testClass, name(), frameworkMethodAnnotations.allAnnotations());
+            Method method = frameworkMethod.getMethod();
+            try {
+                describableFrameworkMethod =
+                        createDescribableFrameworkMethod(method, baseDescription);
+            } catch (IllegalStateException e) {
+                // Defer error until running.
+                describableFrameworkMethod =
+                        new DeferredErrorFrameworkMethod(method, baseDescription, e);
+            }
+        }
+
+        return describableFrameworkMethod;
+    }
+
+    private DescribableFrameworkMethod createDescribableFrameworkMethod(Method method, Description baseDescription) {
+        if (isParameterised()) {
+            if (isNotIgnored()) {
+                Object[] parametersSets = parametersSets();
+                List<InstanceFrameworkMethod> methods
+                        = new ArrayList<InstanceFrameworkMethod>();
+                for (int i = 0; i < parametersSets.length; i++) {
+                    Object parametersSet = parametersSets[i];
+                    Description description = getDescription(parametersSets, i);
+                    methods.add(new InstanceFrameworkMethod(
+                            method, baseDescription.childlessCopy(),
+                            description, parametersSet));
+                }
+
+                return new ParameterisedFrameworkMethod(method, baseDescription, methods);
+            }
+
+            warnIfNoParamsGiven();
+        } else {
+            verifyMethodCanBeRunByStandardRunner(frameworkMethod);
+        }
+
+        // The method to use if it was ignored or was parameterized but had no parameters.
+        return new NonParameterisedFrameworkMethod(method, baseDescription, isIgnored());
+    }
+
+    private void verifyMethodCanBeRunByStandardRunner(FrameworkMethod method) {
+        List<Throwable> errors = new ArrayList<Throwable>();
+        method.validatePublicVoidNoArg(false, errors);
+        if (!errors.isEmpty()) {
+            throw new RuntimeException(errors.get(0));
+        }
     }
 
     public Object[] parametersSets() {
@@ -126,7 +168,7 @@
         return cachedParameters;
     }
 
-    void warnIfNoParamsGiven() {
+    private void warnIfNoParamsGiven() {
         if (isNotIgnored() && isParameterised() && parametersSets().length == 0)
             System.err.println("Method " + name() + " gets empty list of parameters, so it's being ignored!");
     }
diff --git a/src/test/java/junitparams/FilterableTest.java b/src/test/java/junitparams/FilterableTest.java
index 05b2b4c..97e1ea4 100644
--- a/src/test/java/junitparams/FilterableTest.java
+++ b/src/test/java/junitparams/FilterableTest.java
@@ -6,6 +6,7 @@
 import org.junit.runner.Request;
 import org.junit.runner.Result;
 import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.NoTestsRemainException;
 
 import static org.assertj.core.api.Assertions.*;
 
@@ -58,6 +59,20 @@
         assertThat(description.getChildren().get(0).getChildren()).hasSize(2);
     }
 
+    @Test
+    public void shouldApplyFiltersCumulatively() throws Exception {
+        JUnitParamsRunner runner = new JUnitParamsRunner(SampleTestCase.class);
+        // Remove the first method.
+        new SingleMethodFilter("firstTestMethod").apply(runner);
+        try {
+            // Now remove all instances of the second method.
+            new SingleMethodFilter("secondTestMethod").apply(runner);
+            fail("Filtering did not apply cumulatively");
+        } catch (NoTestsRemainException expected) {
+            // expected
+        }
+    }
+
     private Request requestSingleMethodRun(Class<SampleTestCase> clazz, String methodName) {
         return Request.aClass(clazz).filterWith(new SingleMethodFilter(methodName));
     }
diff --git a/src/test/java/junitparams/ParametersReaderProvidersTest.java b/src/test/java/junitparams/ParametersReaderProvidersTest.java
index c4a2bb8..8b4297f 100644
--- a/src/test/java/junitparams/ParametersReaderProvidersTest.java
+++ b/src/test/java/junitparams/ParametersReaderProvidersTest.java
@@ -1,6 +1,5 @@
 package junitparams;
 
-import junitparams.internal.ParameterisedTestMethodRunner;
 import junitparams.internal.TestMethod;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,11 +33,11 @@
 
     @Test
     public void shouldPutProviderClassNameInExceptionMessageForProviderWithNoValidMethods() {
-        ParameterisedTestMethodRunner runner = new ParameterisedTestMethodRunner(getTestMethodWithInvalidProvider());
+        TestMethod testMethod = getTestMethodWithInvalidProvider();
 
         exception.expect(RuntimeException.class);
         exception.expectMessage(ProviderClassWithNoValidMethods.class.getName());
-        runner.method.parametersSets();
+        testMethod.parametersSets();
     }
 
     private TestMethod getTestMethodWithInvalidProvider() {
diff --git a/src/test/java/junitparams/SamplesOfUsageVerificationTest.java b/src/test/java/junitparams/SamplesOfUsageVerificationTest.java
index a485d4e..459a0cd 100644
--- a/src/test/java/junitparams/SamplesOfUsageVerificationTest.java
+++ b/src/test/java/junitparams/SamplesOfUsageVerificationTest.java
@@ -15,8 +15,9 @@
         Result result = JUnitCore.runClasses(SamplesOfUsageTest.class);
 
         assertEquals(0, result.getFailureCount());
-        // TODO(JUnit4.10) - 2 tests are ignored because they do not work when run on the device.
-        assertEquals(2, result.getIgnoreCount());
+        // Android-changed: 5 tests are ignored, see the @Ignore annotated methods in
+        // SamplesOfUsageTest for more details.
+        assertEquals(5, result.getIgnoreCount());
     }
 
 }
diff --git a/src/test/java/junitparams/internal/TestMethodTest.java b/src/test/java/junitparams/internal/TestMethodTest.java
index 2964781..62dc242 100644
--- a/src/test/java/junitparams/internal/TestMethodTest.java
+++ b/src/test/java/junitparams/internal/TestMethodTest.java
@@ -46,7 +46,7 @@
     public void flatTestMethodStructure() throws Exception {
         System.setProperty("JUnitParams.flat", "true");
 
-        Description description = plainTestMethod.describe();
+        Description description = plainTestMethod.describableFrameworkMethod().getDescription();
 
         assertEquals("for_others_to_work(junitparams.internal.TestMethodTest)", description.getDisplayName());
         assertTrue(description.getChildren().isEmpty());
@@ -54,20 +54,26 @@
     }
 
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     public void hierarchicalTestMethodStructure() throws Exception {
         System.clearProperty("JUnitParams.flat");
-        Description description = plainTestMethod.describe();
+        Description description = plainTestMethod.describableFrameworkMethod().getDescription();
 
         assertEquals("forOthersToWork", description.getDisplayName());
         assertEquals("[0] a (forOthersToWork)(junitparams.internal.TestMethodTest)", description.getChildren().get(0).getDisplayName());
         assertEquals("[1] b (forOthersToWork)(junitparams.internal.TestMethodTest)", description.getChildren().get(1).getDisplayName());
     }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     public void hierarchicalArrayTestMethodStructure() throws Exception {
         System.clearProperty("JUnitParams.flat");
-        Description description = arrayTestMethod.describe();
+        Description description = arrayTestMethod.describableFrameworkMethod().getDescription();
 
         assertEquals("forOthersToWorkWithArray", description.getDisplayName());
         assertEquals("[0] a,b (forOthersToWorkWithArray)(junitparams.internal.TestMethodTest)",
diff --git a/src/test/java/junitparams/naming/MacroSubstitutionNamingStrategyTest.java b/src/test/java/junitparams/naming/MacroSubstitutionNamingStrategyTest.java
index b6c5c5c..418b946 100644
--- a/src/test/java/junitparams/naming/MacroSubstitutionNamingStrategyTest.java
+++ b/src/test/java/junitparams/naming/MacroSubstitutionNamingStrategyTest.java
@@ -3,6 +3,7 @@
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
 import junitparams.internal.TestMethod;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.model.FrameworkMethod;
@@ -30,6 +31,9 @@
                             new Object[]{"whenGivenMacroDoesntExist", "{not_existing_macro}"}};
     }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters
     public void testNaming(String methodName, String expectedTestCaseName) throws NoSuchMethodException {
diff --git a/src/test/java/junitparams/naming/NamingStrategyIsUsedByRunnerTest.java b/src/test/java/junitparams/naming/NamingStrategyIsUsedByRunnerTest.java
index 1e0ec24..effda7f 100644
--- a/src/test/java/junitparams/naming/NamingStrategyIsUsedByRunnerTest.java
+++ b/src/test/java/junitparams/naming/NamingStrategyIsUsedByRunnerTest.java
@@ -1,6 +1,7 @@
 package junitparams.naming;
 
 import org.junit.AfterClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.Description;
 import org.junit.runner.Request;
@@ -26,6 +27,9 @@
                 "[1] Well formed name of sampleMethod with param2" + className);
     }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters({"param1", "param2"})
     @TestCaseName("[{index}] Well formed name of {method} with {params}")
diff --git a/src/test/java/junitparams/usage/SamplesOfUsageTest.java b/src/test/java/junitparams/usage/SamplesOfUsageTest.java
index 3c5f410..9a96961 100644
--- a/src/test/java/junitparams/usage/SamplesOfUsageTest.java
+++ b/src/test/java/junitparams/usage/SamplesOfUsageTest.java
@@ -102,12 +102,14 @@
         return new Object[]{new Object[]{"first", 1}, new Object[]{"second", 2}};
     }
 
-    @Ignore("does not work when run on device as it does not have access to the file")
+    // Android-changed: does not work when run on device as it does not have access to the file
+    @Ignore
     @Test
     @FileParameters("src/test/resources/test.csv")
     public void loadParamsFromCsv(int age, String name) { }
 
-    @Ignore("does not work when run on device as it does not have access to the file")
+    // Android-changed: does not work when run on device as it does not have access to the file
+    @Ignore
     @Test
     @FileParameters(value = "src/test/resources/test.csv", mapper = PersonMapper.class)
     public void loadParamsFromAnyFile(PersonTest.Person person) { }
@@ -128,11 +130,17 @@
     @Parameters("please\\, escape commas if you use it here and don't want your parameters to be splitted")
     public void commasInParametersUsage(String phrase) { }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters({ "1,1", "2,2", "3,6" })
     @TestCaseName("factorial({0}) = {1}")
     public void customNamesForTestCase(int argument, int result) { }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters({ "value1, value2", "value3, value4" })
     @TestCaseName("[{index}] {method}: {params}")
@@ -148,6 +156,9 @@
         );
     }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters(method = "mixedParameters")
     @TestCaseName("{0}, {1}, {2}, {3}")
diff --git a/src/test/java/junitparams/usage/person_example/PersonTest.java b/src/test/java/junitparams/usage/person_example/PersonTest.java
index 927204e..b9f15c5 100644
--- a/src/test/java/junitparams/usage/person_example/PersonTest.java
+++ b/src/test/java/junitparams/usage/person_example/PersonTest.java
@@ -56,6 +56,9 @@
         }
     }
 
+    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
+    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
+    @Ignore
     @Test
     @Parameters(method = "adultValues")
     @TestCaseName("Is person with age {0} adult? It's {1} statement.")