Spinner.java revision fef364f75b00e238d28a81e1168bbfc945ce8d23
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.Widget;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlertDialog;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface.OnClickListener;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.DataSetObserver;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
27c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.LayoutInflater;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that displays one child at a time and lets the user pick among them.
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The items in the Spinner come from the {@link Adapter} associated with
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this view.
3641ec65355bd6ded652769725b276d47c54a0d913Scott Main *
3741ec65355bd6ded652769725b276d47c54a0d913Scott Main * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
3841ec65355bd6ded652769725b276d47c54a0d913Scott Main * tutorial</a>.</p>
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#Spinner_prompt
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@Widget
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Spinner extends AbsSpinner implements OnClickListener {
44c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    private static final String TAG = "Spinner";
45c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
46c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    /**
47c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     * Use a dialog window for selecting spinner options.
48c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     */
49c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    public static final int MODE_DIALOG = 0;
50c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
51c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    /**
52c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     * Use a dropdown anchored to the Spinner for selecting spinner options.
53c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     */
54c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    public static final int MODE_DROPDOWN = 1;
55c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
56fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
57fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Use the theme-supplied value to select the dropdown mode.
58fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
59fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    private static final int MODE_THEME = -1;
60fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell
61c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    private SpinnerPopup mPopup;
6268464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell    private DropDownAdapter mTempAdapter;
63fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell
64fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
65fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Construct a new spinner with the given context's theme.
66fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
67fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param context The Context the view is running in, through which it can
68fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        access the current theme, resources, etc.
69fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Spinner(Context context) {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
74fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
75fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Construct a new spinner with the given context's theme and the supplied
76fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * mode of displaying choices. <code>mode</code> may be one of
77fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}.
78fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
79fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param context The Context the view is running in, through which it can
80fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        access the current theme, resources, etc.
81fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param mode Constant describing how the user will select choices from the spinner.
82fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
83fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @see #MODE_DIALOG
84fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @see #MODE_DROPDOWN
85fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
86fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    public Spinner(Context context, int mode) {
87fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell        this(context, null, com.android.internal.R.attr.spinnerStyle, mode);
88fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    }
89fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell
90fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
91fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Construct a new spinner with the given context's theme and the supplied attribute set.
92fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
93fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param context The Context the view is running in, through which it can
94fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        access the current theme, resources, etc.
95fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param attrs The attributes of the XML tag that is inflating the view.
96fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Spinner(Context context, AttributeSet attrs) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, attrs, com.android.internal.R.attr.spinnerStyle);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
101fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
102fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Construct a new spinner with the given context's theme, the supplied attribute set,
103fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * and default style.
104fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
105fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param context The Context the view is running in, through which it can
106fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        access the current theme, resources, etc.
107fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param attrs The attributes of the XML tag that is inflating the view.
108fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param defStyle The default style to apply to this view. If 0, no style
109fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        will be applied (beyond what is included in the theme). This may
110fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        either be an attribute resource, whose value will be retrieved
111fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        from the current theme, or an explicit style resource.
112fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Spinner(Context context, AttributeSet attrs, int defStyle) {
114fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell        this(context, attrs, defStyle, MODE_THEME);
115fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    }
116fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell
117fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    /**
118fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * Construct a new spinner with the given context's theme, the supplied attribute set,
119fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * and default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or
120fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner.
121fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
122fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param context The Context the view is running in, through which it can
123fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        access the current theme, resources, etc.
124fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param attrs The attributes of the XML tag that is inflating the view.
125fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param defStyle The default style to apply to this view. If 0, no style
126fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        will be applied (beyond what is included in the theme). This may
127fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        either be an attribute resource, whose value will be retrieved
128fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *        from the current theme, or an explicit style resource.
129fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @param mode Constant describing how the user will select choices from the spinner.
130fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     *
131fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @see #MODE_DIALOG
132fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     * @see #MODE_DROPDOWN
133fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell     */
134fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell    public Spinner(Context context, AttributeSet attrs, int defStyle, int mode) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs,
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.Spinner, defStyle, 0);
139fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell
140fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell        if (mode == MODE_THEME) {
141fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell            mode = a.getInt(com.android.internal.R.styleable.Spinner_spinnerMode, MODE_DIALOG);
142fef364f75b00e238d28a81e1168bbfc945ce8d23Adam Powell        }
143c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
144c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        switch (mode) {
145c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        case MODE_DIALOG: {
146c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPopup = new DialogPopup();
147c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            break;
148c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
1493f10b1c8f841113b93d2dfecdd84a1dfb1008fafDaisuke Miyakawa
150c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        case MODE_DROPDOWN: {
151c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            final int hintResource = a.getResourceId(
152c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    com.android.internal.R.styleable.Spinner_popupPromptView, 0);
153c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
154c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            DropdownPopup popup = new DropdownPopup(context, attrs, defStyle, hintResource);
155c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
156c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            popup.setBackgroundDrawable(a.getDrawable(
157c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    com.android.internal.R.styleable.Spinner_popupBackground));
158c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            popup.setVerticalOffset(a.getDimensionPixelOffset(
159c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0));
160c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            popup.setHorizontalOffset(a.getDimensionPixelOffset(
161c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0));
162c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
163c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPopup = popup;
164c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            break;
165c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
166c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
167c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
168c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        mPopup.setPromptText(a.getString(com.android.internal.R.styleable.Spinner_prompt));
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
17168464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell
17268464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        // Base constructor can call setAdapter before we initialize mPopup.
17368464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        // Finish setting things up if this happened.
17468464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        if (mTempAdapter != null) {
17568464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell            mPopup.setAdapter(mTempAdapter);
17668464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell            mTempAdapter = null;
17768464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
179c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
180c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    @Override
181c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    public void setAdapter(SpinnerAdapter adapter) {
182c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        super.setAdapter(adapter);
18368464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell
18468464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        if (mPopup != null) {
18568464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell            mPopup.setAdapter(new DropDownAdapter(adapter));
18668464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        } else {
18768464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell            mTempAdapter = new DropDownAdapter(adapter);
18868464a95991d81872a99eefff86a98dd2bd4c8edAdam Powell        }
189c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getBaseline() {
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child = null;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (getChildCount() > 0) {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child = getChildAt(0);
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mAdapter != null && mAdapter.getCount() > 0) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child = makeAndAddView(0);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: We should probably put the child in the recycler
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (child != null) {
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return child.getTop() + child.getBaseline();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2095275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy    @Override
2105275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy    protected void onDetachedFromWindow() {
2115275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy        super.onDetachedFromWindow();
2125275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy
2135275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy        if (mPopup != null && mPopup.isShowing()) {
2145275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy            mPopup.dismiss();
2155275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy        }
2165275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy    }
2175275d69b04aee3f17f698a21d1395e4ba02ac47cRomain Guy
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>A spinner does not support item click events. Calling this method
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * will raise an exception.</p>
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param l this listener will be ignored
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnItemClickListener(OnItemClickListener l) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.view.View#onLayout(boolean,int,int,int,int)
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates and positions all views
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onLayout(boolean changed, int l, int t, int r, int b) {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onLayout(changed, l, t, r, b);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInLayout = true;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layout(0, false);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInLayout = false;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates and positions all views for this Spinner.
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param delta Change in the selected position. +1 moves selection is moving to the right,
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * so views are scrolling to the left. -1 means selection is moving to the left.
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void layout(int delta, boolean animate) {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childrenLeft = mSpinnerPadding.left;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childrenWidth = mRight - mLeft - mSpinnerPadding.left - mSpinnerPadding.right;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDataChanged) {
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handleDataChanged();
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Handle the empty set by removing all views
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mItemCount == 0) {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            resetList();
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNextSelectedPosition >= 0) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setSelectedPositionInt(mNextSelectedPosition);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        recycleAllViews();
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Clear out old views
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeAllViewsInLayout();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make selected view and center it
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFirstPosition = mSelectedPosition;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View sel = makeAndAddView(mSelectedPosition);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int width = sel.getMeasuredWidth();
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sel.offsetLeftAndRight(selectedOffset);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Flush any cached views that did not get reused above
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRecycler.clear();
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkSelectionChanged();
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDataChanged = false;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNeedSync = false;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setNextSelectedPositionInt(mSelectedPosition);
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Obtain a view, either by pulling an existing view from the recycler or
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * by getting a new one from the adapter. If we are animating, make sure
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * there is enough information in the view's layout parameters to animate
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * from the old to new positions.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param position Position in the spinner for the view to obtain
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return A view that has been added to the spinner
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View makeAndAddView(int position) {
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mDataChanged) {
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child = mRecycler.get(position);
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child != null) {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Position the view
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                setUpChild(child);
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return child;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Nothing found in the recycler -- ask the adapter for a view
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child = mAdapter.getView(position, null, this);
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Position the view
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setUpChild(child);
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return child;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Helper for makeAndAddView to set the position of a view
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and fill out its layout paramters.
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param child The view to position
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setUpChild(View child) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Respect layout params that are already in the view. Otherwise
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // make some up...
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ViewGroup.LayoutParams lp = child.getLayoutParams();
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lp == null) {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lp = generateDefaultLayoutParams();
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addViewInLayout(child, 0, lp);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.setSelected(hasFocus());
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get measure specs
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Measure child
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.measure(childWidthSpec, childHeightSpec);
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childLeft;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childRight;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Position vertically based on gravity setting
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childTop = mSpinnerPadding.top
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ((mMeasuredHeight - mSpinnerPadding.bottom -
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childBottom = childTop + child.getMeasuredHeight();
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int width = child.getMeasuredWidth();
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        childLeft = 0;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        childRight = childLeft + width;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        child.layout(childLeft, childTop, childRight, childBottom);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performClick() {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = super.performClick();
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!handled) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled = true;
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
375c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            if (!mPopup.isShowing()) {
376c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                mPopup.show();
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onClick(DialogInterface dialog, int which) {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setSelection(which);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dialog.dismiss();
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the prompt to display when the dialog is shown.
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param prompt the prompt to set
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setPrompt(CharSequence prompt) {
393c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        mPopup.setPromptText(prompt);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the prompt to display when the dialog is shown.
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param promptId the resource ID of the prompt to display when the dialog is shown
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setPromptId(int promptId) {
401c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        setPrompt(getContext().getText(promptId));
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The prompt to display when the dialog is shown
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CharSequence getPrompt() {
408c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        return mPopup.getHintText();
409c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    }
410c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * into a ListAdapter.</p>
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private SpinnerAdapter mAdapter;
4171f09c8314701c1d09be8e350344c58241905677bAdam Powell        private ListAdapter mListAdapter;
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
4201f09c8314701c1d09be8e350344c58241905677bAdam Powell         * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param adapter the Adapter to transform into a ListAdapter
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public DropDownAdapter(SpinnerAdapter adapter) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.mAdapter = adapter;
4261f09c8314701c1d09be8e350344c58241905677bAdam Powell            if (adapter instanceof ListAdapter) {
4271f09c8314701c1d09be8e350344c58241905677bAdam Powell                this.mListAdapter = (ListAdapter) adapter;
4281f09c8314701c1d09be8e350344c58241905677bAdam Powell            }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getCount() {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAdapter == null ? 0 : mAdapter.getCount();
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Object getItem(int position) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAdapter == null ? null : mAdapter.getItem(position);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public long getItemId(int position) {
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAdapter == null ? -1 : mAdapter.getItemId(position);
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public View getView(int position, View convertView, ViewGroup parent) {
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getDropDownView(position, convertView, parent);
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public View getDropDownView(int position, View convertView, ViewGroup parent) {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAdapter == null ? null :
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAdapter.getDropDownView(position, convertView, parent);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean hasStableIds() {
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAdapter != null && mAdapter.hasStableIds();
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void registerDataSetObserver(DataSetObserver observer) {
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAdapter != null) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAdapter.registerDataSetObserver(observer);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void unregisterDataSetObserver(DataSetObserver observer) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAdapter != null) {
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAdapter.unregisterDataSetObserver(observer);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
4691f09c8314701c1d09be8e350344c58241905677bAdam Powell         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
4701f09c8314701c1d09be8e350344c58241905677bAdam Powell         * Otherwise, return true.
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean areAllItemsEnabled() {
4731f09c8314701c1d09be8e350344c58241905677bAdam Powell            final ListAdapter adapter = mListAdapter;
4741f09c8314701c1d09be8e350344c58241905677bAdam Powell            if (adapter != null) {
4751f09c8314701c1d09be8e350344c58241905677bAdam Powell                return adapter.areAllItemsEnabled();
4761f09c8314701c1d09be8e350344c58241905677bAdam Powell            } else {
4771f09c8314701c1d09be8e350344c58241905677bAdam Powell                return true;
4781f09c8314701c1d09be8e350344c58241905677bAdam Powell            }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
4821f09c8314701c1d09be8e350344c58241905677bAdam Powell         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
4831f09c8314701c1d09be8e350344c58241905677bAdam Powell         * Otherwise, return true.
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isEnabled(int position) {
4861f09c8314701c1d09be8e350344c58241905677bAdam Powell            final ListAdapter adapter = mListAdapter;
4871f09c8314701c1d09be8e350344c58241905677bAdam Powell            if (adapter != null) {
4881f09c8314701c1d09be8e350344c58241905677bAdam Powell                return adapter.isEnabled(position);
4891f09c8314701c1d09be8e350344c58241905677bAdam Powell            } else {
4901f09c8314701c1d09be8e350344c58241905677bAdam Powell                return true;
4911f09c8314701c1d09be8e350344c58241905677bAdam Powell            }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getItemViewType(int position) {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getViewTypeCount() {
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 1;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isEmpty() {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getCount() == 0;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
506c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
507c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    /**
508c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     * Implements some sort of popup selection interface for selecting a spinner option.
509c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     * Allows for different spinner modes.
510c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell     */
511c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    private interface SpinnerPopup {
512c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void setAdapter(ListAdapter adapter);
513c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
514c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        /**
515c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * Show the popup
516c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         */
517c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void show();
518c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
519c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        /**
520c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * Dismiss the popup
521c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         */
522c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void dismiss();
523c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
524c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        /**
525c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * @return true if the popup is showing, false otherwise.
526c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         */
527c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public boolean isShowing();
528c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
529c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        /**
530c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * Set hint text to be displayed to the user. This should provide
531c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * a description of the choice being made.
532c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         * @param hintText Hint text to set.
533c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell         */
534c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void setPromptText(CharSequence hintText);
535c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public CharSequence getHintText();
536c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    }
537c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
538c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
539c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private AlertDialog mPopup;
540c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private ListAdapter mListAdapter;
541c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private CharSequence mPrompt;
542c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
543c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void dismiss() {
544c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPopup.dismiss();
545c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPopup = null;
546c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
547c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
548c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public boolean isShowing() {
549c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            return mPopup != null ? mPopup.isShowing() : false;
550c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
551c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
552c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void setAdapter(ListAdapter adapter) {
553c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mListAdapter = adapter;
554c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
555c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
556c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void setPromptText(CharSequence hintText) {
557c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPrompt = hintText;
558c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
559c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
560c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public CharSequence getHintText() {
561c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            return mPrompt;
562c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
563c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
564c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void show() {
565c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
566c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            if (mPrompt != null) {
567c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                builder.setTitle(mPrompt);
568c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            }
569c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mPopup = builder.setSingleChoiceItems(mListAdapter,
570c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    getSelectedItemPosition(), this).show();
571c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
572c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
573c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void onClick(DialogInterface dialog, int which) {
574c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setSelection(which);
575c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            dismiss();
576c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
577c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    }
578c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
579c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
580c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private CharSequence mHintText;
581c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private TextView mHintView;
582c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        private int mHintResource;
583c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
584c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public DropdownPopup(Context context, AttributeSet attrs,
585c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                int defStyleRes, int hintResource) {
586c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            super(context, attrs, 0, defStyleRes);
587c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
588c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mHintResource = hintResource;
589c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
590c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setAnchorView(Spinner.this);
591c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setModal(true);
592c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setPromptPosition(POSITION_PROMPT_BELOW);
593c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setOnItemClickListener(new OnItemClickListener() {
594c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                public void onItemClick(AdapterView parent, View v, int position, long id) {
595c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    Spinner.this.setSelection(position);
596c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                    dismiss();
597c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                }
598c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            });
599c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
600c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
601c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public CharSequence getHintText() {
602c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            return mHintText;
603c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
604c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell
605c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void setPromptText(CharSequence hintText) {
606c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            mHintText = hintText;
607c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            if (mHintView != null) {
608c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                mHintView.setText(hintText);
609c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            }
610c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
6113f10b1c8f841113b93d2dfecdd84a1dfb1008fafDaisuke Miyakawa
6123f10b1c8f841113b93d2dfecdd84a1dfb1008fafDaisuke Miyakawa        @Override
613c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        public void show() {
614c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            if (mHintView == null) {
615c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                final TextView textView = (TextView) LayoutInflater.from(getContext()).inflate(
616c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                        mHintResource, null).findViewById(com.android.internal.R.id.text1);
617c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                textView.setText(mHintText);
618c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                setPromptView(textView);
619c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell                mHintView = textView;
620c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            }
621c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            super.show();
622c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
623c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell            setSelection(Spinner.this.getSelectedItemPosition());
624c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell        }
625c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell    }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
627