API review feedback for ThemedSpinnerAdapter, Spinner

Moves themed interface out of Spinner and extends SpinnerAdapter, updates
Spinner constructor to take a Theme rather than a Context.

Does NOT change BaseAdapter to implement ThemedSpinnerAdapter, because
the BaseAdapter class does not have any notion of layout inflation and
that would break the contract implied by ThemedSpinnerAdapter.

Bug: 21571899
Change-Id: Id7e8d630458857ce6c93a6a8b8f920e169ee1152
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index ae94a10..260854f 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -50,8 +50,7 @@
  * or to have some of data besides toString() results fill the views,
  * override {@link #getView(int, View, ViewGroup)} to return the type of view you want.
  */
-public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
-        Spinner.ThemedSpinnerAdapter {
+public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
     /**
      * Contains the list of objects that represent the data of this ArrayAdapter.
      * The content of this list is referred to as "the array" in the documentation.
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index d8ce60c..9fb98db 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -38,7 +38,7 @@
  * columns.
  */
 public abstract class CursorAdapter extends BaseAdapter implements Filterable,
-        CursorFilter.CursorFilterClient, Spinner.ThemedSpinnerAdapter {
+        CursorFilter.CursorFilterClient, ThemedSpinnerAdapter {
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 2008ba8f..e7760ee 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -51,7 +51,7 @@
  * </ul>
  * If no appropriate binding can be found, an {@link IllegalStateException} is thrown.
  */
-public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.ThemedSpinnerAdapter {
+public class SimpleAdapter extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
     private int[] mTo;
     private String[] mFrom;
     private ViewBinder mViewBinder;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 095cc44..6fe34dd 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -26,6 +26,7 @@
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
@@ -217,24 +218,24 @@
      *                    Can be 0 to not look for defaults.
      * @param mode Constant describing how the user will select choices from
      *             the spinner.
-     * @param popupContext The context against which the dialog or dropdown
-     *                     popup will be inflated. Can be null to use the view
-     *                     context. If set, this will override any value
-     *                     specified by
-     *                     {@link android.R.styleable#Spinner_popupTheme}.
+     * @param popupTheme The theme against which the dialog or dropdown popup
+     *                   should be inflated. May be {@code null} to use the
+     *                   view theme. If set, this will override any value
+     *                   specified by
+     *                   {@link android.R.styleable#Spinner_popupTheme}.
      *
      * @see #MODE_DIALOG
      * @see #MODE_DROPDOWN
      */
     public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode,
-            Context popupContext) {
+            Theme popupTheme) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
 
-        if (popupContext != null) {
-            mPopupContext = popupContext;
+        if (popupTheme != null) {
+            mPopupContext = new ContextThemeWrapper(context, popupTheme);
         } else {
             final int popupThemeResId = a.getResourceId(R.styleable.Spinner_popupTheme, 0);
             if (popupThemeResId != 0) {
@@ -932,9 +933,8 @@
                 mListAdapter = (ListAdapter) adapter;
             }
 
-            if (dropDownTheme != null && adapter instanceof Spinner.ThemedSpinnerAdapter) {
-                final Spinner.ThemedSpinnerAdapter themedAdapter =
-                        (Spinner.ThemedSpinnerAdapter) adapter;
+            if (dropDownTheme != null && adapter instanceof ThemedSpinnerAdapter) {
+                final ThemedSpinnerAdapter themedAdapter = (ThemedSpinnerAdapter) adapter;
                 if (themedAdapter.getDropDownViewTheme() == null) {
                     themedAdapter.setDropDownViewTheme(dropDownTheme);
                 }
@@ -1263,20 +1263,4 @@
         }
     }
 
-    public interface ThemedSpinnerAdapter {
-        /**
-         * Sets the {@link Resources.Theme} against which drop-down views are
-         * inflated.
-         *
-         * @param theme the context against which to inflate drop-down views
-         * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup)
-         */
-        public void setDropDownViewTheme(Resources.Theme theme);
-
-        /**
-         * @return The {@link Resources.Theme} against which drop-down views are
-         *         inflated.
-         */
-        public Resources.Theme getDropDownViewTheme();
-    }
 }
diff --git a/core/java/android/widget/ThemedSpinnerAdapter.java b/core/java/android/widget/ThemedSpinnerAdapter.java
new file mode 100644
index 0000000..6d92620
--- /dev/null
+++ b/core/java/android/widget/ThemedSpinnerAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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 android.widget;
+
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * An extension of SpinnerAdapter that is capable of inflating drop-down views
+ * against a different theme than normal views.
+ * <p>
+ * Classes that implement this interface should use the theme provided to
+ * {@link #setDropDownViewTheme(Theme)} when creating views in
+ * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}.
+ */
+public interface ThemedSpinnerAdapter extends SpinnerAdapter {
+    /**
+     * Sets the {@link Resources.Theme} against which drop-down views are
+     * inflated.
+     *
+     * @param theme the context against which to inflate drop-down views, or
+     *              {@code null} to use the default theme
+     * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup)
+     */
+    void setDropDownViewTheme(@Nullable Resources.Theme theme);
+
+    /**
+     * Returns the value previously set by a call to
+     * {@link #setDropDownViewTheme(Theme)}.
+     *
+     * @return the {@link Resources.Theme} against which drop-down views are
+     *         inflated, or {@code null} if one has not been explicitly set
+     */
+    @Nullable
+    Resources.Theme getDropDownViewTheme();
+}