This was almost certainly my fault, but as I look at the implementation of Sets.cartesianProduct, I think its `contains` method made the assumption that `ImmutableSet.asList().indexOf` was O(1), which is no longer the case for Android.  It should probably get a specific `contains` implementation that actually is O(sets), not O(sets*setSize).
* <p>The returned set and its constituent sets use {@code equals} to decide whether two elements
   * are identical, even if the input set uses a different concept of equivalence.
   *
   * <p><i>Performance notes:</i> the memory usage of the returned set is only {@code O(n)}. When
   * the result set is constructed, the input set is merely copied. Only as the result set is
   * iterated are the individual subsets created. Each of these subsets occupies an additional O(n)
   * memory but only for as long as the user retains a reference to it. That is, the set returned by
   * {@code combinations} does not retain the individual subsets.
   *
   * @param set the set of elements to take combinations of
   * @param size the number of elements per combination
   * @return the set of all combinations of {@code size} elements from {@code set}
   * @throws IllegalArgumentException if {@code size} is not between 0 and {@code set.size()}
   *     inclusive
   * @throws NullPointerException if {@code set} is or contains {@code null}
   * @since 23.0
   */
  @Beta
  public static <E> Set<Set<E>> combinations(Set<E> set, final int size) {
    final ImmutableMap<E, Integer> index = Maps.indexMap(set);
    checkNonnegative(size, "size");
    checkArgument(size <= index.size(), "size (%s) must be <= set.size() (%s)", size, index.size());
    if (size == 0) {
      return ImmutableSet.<Set<E>>of(ImmutableSet.<E>of());
    } else if (size == index.size()) {
      return ImmutableSet.<Set<E>>of(index.keySet());
    }
    return new AbstractSet<Set<E>>() {
      @Override
      public boolean contains(@Nullable Object o) {