• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.widget;
18 
19 import android.annotation.Widget;
20 import android.app.AlertDialog;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.DialogInterface.OnClickListener;
24 import android.content.res.TypedArray;
25 import android.database.DataSetObserver;
26 import android.graphics.Rect;
27 import android.graphics.drawable.Drawable;
28 import android.util.AttributeSet;
29 import android.view.Gravity;
30 import android.view.View;
31 import android.view.ViewGroup;
32 
33 
34 /**
35  * A view that displays one child at a time and lets the user pick among them.
36  * The items in the Spinner come from the {@link Adapter} associated with
37  * this view.
38  *
39  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
40  * tutorial</a>.</p>
41  *
42  * @attr ref android.R.styleable#Spinner_prompt
43  */
44 @Widget
45 public class Spinner extends AbsSpinner implements OnClickListener {
46     private static final String TAG = "Spinner";
47 
48     // Only measure this many items to get a decent max width.
49     private static final int MAX_ITEMS_MEASURED = 15;
50 
51     /**
52      * Use a dialog window for selecting spinner options.
53      */
54     public static final int MODE_DIALOG = 0;
55 
56     /**
57      * Use a dropdown anchored to the Spinner for selecting spinner options.
58      */
59     public static final int MODE_DROPDOWN = 1;
60 
61     /**
62      * Use the theme-supplied value to select the dropdown mode.
63      */
64     private static final int MODE_THEME = -1;
65 
66     private SpinnerPopup mPopup;
67     private DropDownAdapter mTempAdapter;
68     int mDropDownWidth;
69 
70     private int mGravity;
71 
72     private Rect mTempRect = new Rect();
73 
74     /**
75      * Construct a new spinner with the given context's theme.
76      *
77      * @param context The Context the view is running in, through which it can
78      *        access the current theme, resources, etc.
79      */
Spinner(Context context)80     public Spinner(Context context) {
81         this(context, null);
82     }
83 
84     /**
85      * Construct a new spinner with the given context's theme and the supplied
86      * mode of displaying choices. <code>mode</code> may be one of
87      * {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}.
88      *
89      * @param context The Context the view is running in, through which it can
90      *        access the current theme, resources, etc.
91      * @param mode Constant describing how the user will select choices from the spinner.
92      *
93      * @see #MODE_DIALOG
94      * @see #MODE_DROPDOWN
95      */
Spinner(Context context, int mode)96     public Spinner(Context context, int mode) {
97         this(context, null, com.android.internal.R.attr.spinnerStyle, mode);
98     }
99 
100     /**
101      * Construct a new spinner with the given context's theme and the supplied attribute set.
102      *
103      * @param context The Context the view is running in, through which it can
104      *        access the current theme, resources, etc.
105      * @param attrs The attributes of the XML tag that is inflating the view.
106      */
Spinner(Context context, AttributeSet attrs)107     public Spinner(Context context, AttributeSet attrs) {
108         this(context, attrs, com.android.internal.R.attr.spinnerStyle);
109     }
110 
111     /**
112      * Construct a new spinner with the given context's theme, the supplied attribute set,
113      * and default style.
114      *
115      * @param context The Context the view is running in, through which it can
116      *        access the current theme, resources, etc.
117      * @param attrs The attributes of the XML tag that is inflating the view.
118      * @param defStyle The default style to apply to this view. If 0, no style
119      *        will be applied (beyond what is included in the theme). This may
120      *        either be an attribute resource, whose value will be retrieved
121      *        from the current theme, or an explicit style resource.
122      */
Spinner(Context context, AttributeSet attrs, int defStyle)123     public Spinner(Context context, AttributeSet attrs, int defStyle) {
124         this(context, attrs, defStyle, MODE_THEME);
125     }
126 
127     /**
128      * Construct a new spinner with the given context's theme, the supplied attribute set,
129      * and default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or
130      * {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner.
131      *
132      * @param context The Context the view is running in, through which it can
133      *        access the current theme, resources, etc.
134      * @param attrs The attributes of the XML tag that is inflating the view.
135      * @param defStyle The default style to apply to this view. If 0, no style
136      *        will be applied (beyond what is included in the theme). This may
137      *        either be an attribute resource, whose value will be retrieved
138      *        from the current theme, or an explicit style resource.
139      * @param mode Constant describing how the user will select choices from the spinner.
140      *
141      * @see #MODE_DIALOG
142      * @see #MODE_DROPDOWN
143      */
Spinner(Context context, AttributeSet attrs, int defStyle, int mode)144     public Spinner(Context context, AttributeSet attrs, int defStyle, int mode) {
145         super(context, attrs, defStyle);
146 
147         TypedArray a = context.obtainStyledAttributes(attrs,
148                 com.android.internal.R.styleable.Spinner, defStyle, 0);
149 
150         if (mode == MODE_THEME) {
151             mode = a.getInt(com.android.internal.R.styleable.Spinner_spinnerMode, MODE_DIALOG);
152         }
153 
154         switch (mode) {
155         case MODE_DIALOG: {
156             mPopup = new DialogPopup();
157             break;
158         }
159 
160         case MODE_DROPDOWN: {
161             DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
162 
163             mDropDownWidth = a.getLayoutDimension(
164                     com.android.internal.R.styleable.Spinner_dropDownWidth,
165                     ViewGroup.LayoutParams.WRAP_CONTENT);
166             popup.setBackgroundDrawable(a.getDrawable(
167                     com.android.internal.R.styleable.Spinner_popupBackground));
168             final int verticalOffset = a.getDimensionPixelOffset(
169                     com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0);
170             if (verticalOffset != 0) {
171                 popup.setVerticalOffset(verticalOffset);
172             }
173 
174             final int horizontalOffset = a.getDimensionPixelOffset(
175                     com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0);
176             if (horizontalOffset != 0) {
177                 popup.setHorizontalOffset(horizontalOffset);
178             }
179 
180             mPopup = popup;
181             break;
182         }
183         }
184 
185         mGravity = a.getInt(com.android.internal.R.styleable.Spinner_gravity, Gravity.CENTER);
186 
187         mPopup.setPromptText(a.getString(com.android.internal.R.styleable.Spinner_prompt));
188 
189         a.recycle();
190 
191         // Base constructor can call setAdapter before we initialize mPopup.
192         // Finish setting things up if this happened.
193         if (mTempAdapter != null) {
194             mPopup.setAdapter(mTempAdapter);
195             mTempAdapter = null;
196         }
197     }
198 
199     /**
200      * Describes how the selected item view is positioned. Currently only the horizontal component
201      * is used. The default is determined by the current theme.
202      *
203      * @param gravity See {@link android.view.Gravity}
204      *
205      * @attr ref android.R.styleable#Spinner_gravity
206      */
setGravity(int gravity)207     public void setGravity(int gravity) {
208         if (mGravity != gravity) {
209             if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
210                 gravity |= Gravity.LEFT;
211             }
212             mGravity = gravity;
213             requestLayout();
214         }
215     }
216 
217     @Override
setAdapter(SpinnerAdapter adapter)218     public void setAdapter(SpinnerAdapter adapter) {
219         super.setAdapter(adapter);
220 
221         if (mPopup != null) {
222             mPopup.setAdapter(new DropDownAdapter(adapter));
223         } else {
224             mTempAdapter = new DropDownAdapter(adapter);
225         }
226     }
227 
228     @Override
getBaseline()229     public int getBaseline() {
230         View child = null;
231 
232         if (getChildCount() > 0) {
233             child = getChildAt(0);
234         } else if (mAdapter != null && mAdapter.getCount() > 0) {
235             child = makeAndAddView(0);
236             mRecycler.put(0, child);
237             removeAllViewsInLayout();
238         }
239 
240         if (child != null) {
241             final int childBaseline = child.getBaseline();
242             return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
243         } else {
244             return -1;
245         }
246     }
247 
248     @Override
onDetachedFromWindow()249     protected void onDetachedFromWindow() {
250         super.onDetachedFromWindow();
251 
252         if (mPopup != null && mPopup.isShowing()) {
253             mPopup.dismiss();
254         }
255     }
256 
257     /**
258      * <p>A spinner does not support item click events. Calling this method
259      * will raise an exception.</p>
260      *
261      * @param l this listener will be ignored
262      */
263     @Override
setOnItemClickListener(OnItemClickListener l)264     public void setOnItemClickListener(OnItemClickListener l) {
265         throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
266     }
267 
268     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)269     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
270         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
271         if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
272             final int measuredWidth = getMeasuredWidth();
273             setMeasuredDimension(Math.min(Math.max(measuredWidth,
274                     measureContentWidth(getAdapter(), getBackground())),
275                     MeasureSpec.getSize(widthMeasureSpec)),
276                     getMeasuredHeight());
277         }
278     }
279 
280     /**
281      * @see android.view.View#onLayout(boolean,int,int,int,int)
282      *
283      * Creates and positions all views
284      *
285      */
286     @Override
onLayout(boolean changed, int l, int t, int r, int b)287     protected void onLayout(boolean changed, int l, int t, int r, int b) {
288         super.onLayout(changed, l, t, r, b);
289         mInLayout = true;
290         layout(0, false);
291         mInLayout = false;
292     }
293 
294     /**
295      * Creates and positions all views for this Spinner.
296      *
297      * @param delta Change in the selected position. +1 moves selection is moving to the right,
298      * so views are scrolling to the left. -1 means selection is moving to the left.
299      */
300     @Override
layout(int delta, boolean animate)301     void layout(int delta, boolean animate) {
302         int childrenLeft = mSpinnerPadding.left;
303         int childrenWidth = mRight - mLeft - mSpinnerPadding.left - mSpinnerPadding.right;
304 
305         if (mDataChanged) {
306             handleDataChanged();
307         }
308 
309         // Handle the empty set by removing all views
310         if (mItemCount == 0) {
311             resetList();
312             return;
313         }
314 
315         if (mNextSelectedPosition >= 0) {
316             setSelectedPositionInt(mNextSelectedPosition);
317         }
318 
319         recycleAllViews();
320 
321         // Clear out old views
322         removeAllViewsInLayout();
323 
324         // Make selected view and position it
325         mFirstPosition = mSelectedPosition;
326         View sel = makeAndAddView(mSelectedPosition);
327         int width = sel.getMeasuredWidth();
328         int selectedOffset = childrenLeft;
329         switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
330             case Gravity.CENTER_HORIZONTAL:
331                 selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
332                 break;
333             case Gravity.RIGHT:
334                 selectedOffset = childrenLeft + childrenWidth - width;
335                 break;
336         }
337         sel.offsetLeftAndRight(selectedOffset);
338 
339         // Flush any cached views that did not get reused above
340         mRecycler.clear();
341 
342         invalidate();
343 
344         checkSelectionChanged();
345 
346         mDataChanged = false;
347         mNeedSync = false;
348         setNextSelectedPositionInt(mSelectedPosition);
349     }
350 
351     /**
352      * Obtain a view, either by pulling an existing view from the recycler or
353      * by getting a new one from the adapter. If we are animating, make sure
354      * there is enough information in the view's layout parameters to animate
355      * from the old to new positions.
356      *
357      * @param position Position in the spinner for the view to obtain
358      * @return A view that has been added to the spinner
359      */
makeAndAddView(int position)360     private View makeAndAddView(int position) {
361 
362         View child;
363 
364         if (!mDataChanged) {
365             child = mRecycler.get(position);
366             if (child != null) {
367                 // Position the view
368                 setUpChild(child);
369 
370                 return child;
371             }
372         }
373 
374         // Nothing found in the recycler -- ask the adapter for a view
375         child = mAdapter.getView(position, null, this);
376 
377         // Position the view
378         setUpChild(child);
379 
380         return child;
381     }
382 
383     /**
384      * Helper for makeAndAddView to set the position of a view
385      * and fill out its layout paramters.
386      *
387      * @param child The view to position
388      */
setUpChild(View child)389     private void setUpChild(View child) {
390 
391         // Respect layout params that are already in the view. Otherwise
392         // make some up...
393         ViewGroup.LayoutParams lp = child.getLayoutParams();
394         if (lp == null) {
395             lp = generateDefaultLayoutParams();
396         }
397 
398         addViewInLayout(child, 0, lp);
399 
400         child.setSelected(hasFocus());
401 
402         // Get measure specs
403         int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
404                 mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
405         int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
406                 mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
407 
408         // Measure child
409         child.measure(childWidthSpec, childHeightSpec);
410 
411         int childLeft;
412         int childRight;
413 
414         // Position vertically based on gravity setting
415         int childTop = mSpinnerPadding.top
416                 + ((getMeasuredHeight() - mSpinnerPadding.bottom -
417                         mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
418         int childBottom = childTop + child.getMeasuredHeight();
419 
420         int width = child.getMeasuredWidth();
421         childLeft = 0;
422         childRight = childLeft + width;
423 
424         child.layout(childLeft, childTop, childRight, childBottom);
425     }
426 
427     @Override
performClick()428     public boolean performClick() {
429         boolean handled = super.performClick();
430 
431         if (!handled) {
432             handled = true;
433 
434             if (!mPopup.isShowing()) {
435                 mPopup.show();
436             }
437         }
438 
439         return handled;
440     }
441 
onClick(DialogInterface dialog, int which)442     public void onClick(DialogInterface dialog, int which) {
443         setSelection(which);
444         dialog.dismiss();
445     }
446 
447     /**
448      * Sets the prompt to display when the dialog is shown.
449      * @param prompt the prompt to set
450      */
setPrompt(CharSequence prompt)451     public void setPrompt(CharSequence prompt) {
452         mPopup.setPromptText(prompt);
453     }
454 
455     /**
456      * Sets the prompt to display when the dialog is shown.
457      * @param promptId the resource ID of the prompt to display when the dialog is shown
458      */
setPromptId(int promptId)459     public void setPromptId(int promptId) {
460         setPrompt(getContext().getText(promptId));
461     }
462 
463     /**
464      * @return The prompt to display when the dialog is shown
465      */
getPrompt()466     public CharSequence getPrompt() {
467         return mPopup.getHintText();
468     }
469 
measureContentWidth(SpinnerAdapter adapter, Drawable background)470     int measureContentWidth(SpinnerAdapter adapter, Drawable background) {
471         if (adapter == null) {
472             return 0;
473         }
474 
475         int width = 0;
476         View itemView = null;
477         int itemType = 0;
478         final int widthMeasureSpec =
479             MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
480         final int heightMeasureSpec =
481             MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
482 
483         // Make sure the number of items we'll measure is capped. If it's a huge data set
484         // with wildly varying sizes, oh well.
485         int start = Math.max(0, getSelectedItemPosition());
486         final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
487         final int count = end - start;
488         start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
489         for (int i = start; i < end; i++) {
490             final int positionType = adapter.getItemViewType(i);
491             if (positionType != itemType) {
492                 itemType = positionType;
493                 itemView = null;
494             }
495             itemView = adapter.getView(i, itemView, this);
496             if (itemView.getLayoutParams() == null) {
497                 itemView.setLayoutParams(new ViewGroup.LayoutParams(
498                         ViewGroup.LayoutParams.WRAP_CONTENT,
499                         ViewGroup.LayoutParams.WRAP_CONTENT));
500             }
501             itemView.measure(widthMeasureSpec, heightMeasureSpec);
502             width = Math.max(width, itemView.getMeasuredWidth());
503         }
504 
505         // Add background padding to measured width
506         if (background != null) {
507             background.getPadding(mTempRect);
508             width += mTempRect.left + mTempRect.right;
509         }
510 
511         return width;
512     }
513 
514     /**
515      * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
516      * into a ListAdapter.</p>
517      */
518     private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
519         private SpinnerAdapter mAdapter;
520         private ListAdapter mListAdapter;
521 
522         /**
523          * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
524          *
525          * @param adapter the Adapter to transform into a ListAdapter
526          */
DropDownAdapter(SpinnerAdapter adapter)527         public DropDownAdapter(SpinnerAdapter adapter) {
528             this.mAdapter = adapter;
529             if (adapter instanceof ListAdapter) {
530                 this.mListAdapter = (ListAdapter) adapter;
531             }
532         }
533 
getCount()534         public int getCount() {
535             return mAdapter == null ? 0 : mAdapter.getCount();
536         }
537 
getItem(int position)538         public Object getItem(int position) {
539             return mAdapter == null ? null : mAdapter.getItem(position);
540         }
541 
getItemId(int position)542         public long getItemId(int position) {
543             return mAdapter == null ? -1 : mAdapter.getItemId(position);
544         }
545 
getView(int position, View convertView, ViewGroup parent)546         public View getView(int position, View convertView, ViewGroup parent) {
547             return getDropDownView(position, convertView, parent);
548         }
549 
getDropDownView(int position, View convertView, ViewGroup parent)550         public View getDropDownView(int position, View convertView, ViewGroup parent) {
551             return mAdapter == null ? null :
552                     mAdapter.getDropDownView(position, convertView, parent);
553         }
554 
hasStableIds()555         public boolean hasStableIds() {
556             return mAdapter != null && mAdapter.hasStableIds();
557         }
558 
registerDataSetObserver(DataSetObserver observer)559         public void registerDataSetObserver(DataSetObserver observer) {
560             if (mAdapter != null) {
561                 mAdapter.registerDataSetObserver(observer);
562             }
563         }
564 
unregisterDataSetObserver(DataSetObserver observer)565         public void unregisterDataSetObserver(DataSetObserver observer) {
566             if (mAdapter != null) {
567                 mAdapter.unregisterDataSetObserver(observer);
568             }
569         }
570 
571         /**
572          * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
573          * Otherwise, return true.
574          */
areAllItemsEnabled()575         public boolean areAllItemsEnabled() {
576             final ListAdapter adapter = mListAdapter;
577             if (adapter != null) {
578                 return adapter.areAllItemsEnabled();
579             } else {
580                 return true;
581             }
582         }
583 
584         /**
585          * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
586          * Otherwise, return true.
587          */
isEnabled(int position)588         public boolean isEnabled(int position) {
589             final ListAdapter adapter = mListAdapter;
590             if (adapter != null) {
591                 return adapter.isEnabled(position);
592             } else {
593                 return true;
594             }
595         }
596 
getItemViewType(int position)597         public int getItemViewType(int position) {
598             return 0;
599         }
600 
getViewTypeCount()601         public int getViewTypeCount() {
602             return 1;
603         }
604 
isEmpty()605         public boolean isEmpty() {
606             return getCount() == 0;
607         }
608     }
609 
610     /**
611      * Implements some sort of popup selection interface for selecting a spinner option.
612      * Allows for different spinner modes.
613      */
614     private interface SpinnerPopup {
setAdapter(ListAdapter adapter)615         public void setAdapter(ListAdapter adapter);
616 
617         /**
618          * Show the popup
619          */
show()620         public void show();
621 
622         /**
623          * Dismiss the popup
624          */
dismiss()625         public void dismiss();
626 
627         /**
628          * @return true if the popup is showing, false otherwise.
629          */
isShowing()630         public boolean isShowing();
631 
632         /**
633          * Set hint text to be displayed to the user. This should provide
634          * a description of the choice being made.
635          * @param hintText Hint text to set.
636          */
setPromptText(CharSequence hintText)637         public void setPromptText(CharSequence hintText);
getHintText()638         public CharSequence getHintText();
639     }
640 
641     private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
642         private AlertDialog mPopup;
643         private ListAdapter mListAdapter;
644         private CharSequence mPrompt;
645 
dismiss()646         public void dismiss() {
647             mPopup.dismiss();
648             mPopup = null;
649         }
650 
isShowing()651         public boolean isShowing() {
652             return mPopup != null ? mPopup.isShowing() : false;
653         }
654 
setAdapter(ListAdapter adapter)655         public void setAdapter(ListAdapter adapter) {
656             mListAdapter = adapter;
657         }
658 
setPromptText(CharSequence hintText)659         public void setPromptText(CharSequence hintText) {
660             mPrompt = hintText;
661         }
662 
getHintText()663         public CharSequence getHintText() {
664             return mPrompt;
665         }
666 
show()667         public void show() {
668             AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
669             if (mPrompt != null) {
670                 builder.setTitle(mPrompt);
671             }
672             mPopup = builder.setSingleChoiceItems(mListAdapter,
673                     getSelectedItemPosition(), this).show();
674         }
675 
onClick(DialogInterface dialog, int which)676         public void onClick(DialogInterface dialog, int which) {
677             setSelection(which);
678             dismiss();
679         }
680     }
681 
682     private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
683         private CharSequence mHintText;
684         private ListAdapter mAdapter;
685 
DropdownPopup(Context context, AttributeSet attrs, int defStyleRes)686         public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) {
687             super(context, attrs, 0, defStyleRes);
688 
689             setAnchorView(Spinner.this);
690             setModal(true);
691             setPromptPosition(POSITION_PROMPT_ABOVE);
692             setOnItemClickListener(new OnItemClickListener() {
693                 public void onItemClick(AdapterView parent, View v, int position, long id) {
694                     Spinner.this.setSelection(position);
695                     dismiss();
696                 }
697             });
698         }
699 
700         @Override
setAdapter(ListAdapter adapter)701         public void setAdapter(ListAdapter adapter) {
702             super.setAdapter(adapter);
703             mAdapter = adapter;
704         }
705 
getHintText()706         public CharSequence getHintText() {
707             return mHintText;
708         }
709 
setPromptText(CharSequence hintText)710         public void setPromptText(CharSequence hintText) {
711             // Hint text is ignored for dropdowns, but maintain it here.
712             mHintText = hintText;
713         }
714 
715         @Override
show()716         public void show() {
717             final int spinnerPaddingLeft = Spinner.this.getPaddingLeft();
718             if (mDropDownWidth == WRAP_CONTENT) {
719                 final int spinnerWidth = Spinner.this.getWidth();
720                 final int spinnerPaddingRight = Spinner.this.getPaddingRight();
721                 setContentWidth(Math.max(
722                         measureContentWidth((SpinnerAdapter) mAdapter, getBackground()),
723                         spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
724             } else if (mDropDownWidth == MATCH_PARENT) {
725                 final int spinnerWidth = Spinner.this.getWidth();
726                 final int spinnerPaddingRight = Spinner.this.getPaddingRight();
727                 setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
728             } else {
729                 setContentWidth(mDropDownWidth);
730             }
731             final Drawable background = getBackground();
732             int bgOffset = 0;
733             if (background != null) {
734                 background.getPadding(mTempRect);
735                 bgOffset = -mTempRect.left;
736             }
737             setHorizontalOffset(bgOffset + spinnerPaddingLeft);
738             setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
739             super.show();
740             getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
741             setSelection(Spinner.this.getSelectedItemPosition());
742         }
743     }
744 }
745