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/api/current.txt b/api/current.txt
index d38e75a..b909e1e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -39614,7 +39614,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -39855,7 +39855,7 @@
     method public abstract void onCheckedChanged(android.widget.CompoundButton, boolean);
   }
 
-  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
@@ -41120,7 +41120,7 @@
     method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
   }
 
-  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
     method public int getCount();
     method public android.content.res.Resources.Theme getDropDownViewTheme();
@@ -41249,7 +41249,7 @@
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int);
-    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.Context);
+    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.res.Resources.Theme);
     method public int getDropDownHorizontalOffset();
     method public int getDropDownVerticalOffset();
     method public int getDropDownWidth();
@@ -41270,11 +41270,6 @@
     field public static final int MODE_DROPDOWN = 1; // 0x1
   }
 
-  public static abstract interface Spinner.ThemedSpinnerAdapter {
-    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
-    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
-  }
-
   public abstract interface SpinnerAdapter implements android.widget.Adapter {
     method public abstract android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
   }
@@ -41676,6 +41671,11 @@
     field public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
   }
 
+  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
   public class TimePicker extends android.widget.FrameLayout {
     ctor public TimePicker(android.content.Context);
     ctor public TimePicker(android.content.Context, android.util.AttributeSet);
diff --git a/api/system-current.txt b/api/system-current.txt
index 44d8c8e..a0a9cea 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -42186,7 +42186,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -42427,7 +42427,7 @@
     method public abstract void onCheckedChanged(android.widget.CompoundButton, boolean);
   }
 
-  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
@@ -43692,7 +43692,7 @@
     method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
   }
 
-  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
+  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
     method public int getCount();
     method public android.content.res.Resources.Theme getDropDownViewTheme();
@@ -43821,7 +43821,7 @@
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int);
-    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.Context);
+    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.res.Resources.Theme);
     method public int getDropDownHorizontalOffset();
     method public int getDropDownVerticalOffset();
     method public int getDropDownWidth();
@@ -43842,11 +43842,6 @@
     field public static final int MODE_DROPDOWN = 1; // 0x1
   }
 
-  public static abstract interface Spinner.ThemedSpinnerAdapter {
-    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
-    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
-  }
-
   public abstract interface SpinnerAdapter implements android.widget.Adapter {
     method public abstract android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
   }
@@ -44248,6 +44243,11 @@
     field public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
   }
 
+  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
   public class TimePicker extends android.widget.FrameLayout {
     ctor public TimePicker(android.content.Context);
     ctor public TimePicker(android.content.Context, android.util.AttributeSet);
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();
+}