13565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani/*
249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Copyright (C) 2014 The Android Open Source Project
33565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani *
43565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * Licensed under the Apache License, Version 2.0 (the "License");
53565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * you may not use this file except in compliance with the License.
63565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * You may obtain a copy of the License at
73565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani *
83565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani *      http://www.apache.org/licenses/LICENSE-2.0
93565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani *
103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * Unless required by applicable law or agreed to in writing, software
113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * distributed under the License is distributed on an "AS IS" BASIS,
123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * See the License for the specific language governing permissions and
143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani * limitations under the License.
153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani */
163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1749c78900da0d43140fb602431fb93212bd7f6c70Chris Banespackage android.support.v7.widget;
183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.content.Context;
20ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banesimport android.content.res.TypedArray;
213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.database.DataSetObserver;
223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.graphics.Rect;
233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.graphics.drawable.Drawable;
2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.os.Build;
253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.os.Handler;
2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.os.SystemClock;
2749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.text.TextUtilsCompat;
2849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.MotionEventCompat;
2949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorCompat;
3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.widget.ListViewAutoScrollHelper;
3149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.widget.PopupWindowCompat;
32da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R;
335ec2faa01bc6790bc015e0d5748dc0482ae8c0f2Chris Banesimport android.support.v7.internal.widget.AppCompatPopupWindow;
3449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v7.internal.widget.ListViewCompat;
353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.util.AttributeSet;
363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.util.Log;
3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.Gravity;
383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.KeyEvent;
393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.MotionEvent;
403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.View;
413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.View.MeasureSpec;
423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.View.OnTouchListener;
4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.ViewConfiguration;
443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.ViewGroup;
453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport android.view.ViewParent;
4649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.AbsListView;
4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.AdapterView;
4849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.LinearLayout;
4949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.ListAdapter;
5049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.ListView;
5149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.PopupWindow;
523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
53ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banesimport java.lang.reflect.Method;
543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewaniimport java.util.Locale;
553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani/**
5749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Static library support version of the framework's {@link android.widget.ListPopupWindow}.
5849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Used to write apps that run on platforms prior to Android L. When running
5949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * on Android L or above, this implementation is still used; it does not try
6049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * to switch to the framework's implementation. See the framework SDK
6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * documentation for a class overview.
623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani *
6349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * @see android.widget.ListPopupWindow
643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani */
653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewanipublic class ListPopupWindow {
663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private static final String TAG = "ListPopupWindow";
673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private static final boolean DEBUG = false;
683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
7049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * This value controls the length of time that the user
7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * must leave a pointer down without scrolling to expand
7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the autocomplete dropdown list to cover the IME.
733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private static final int EXPAND_LIST_TIMEOUT = 250;
753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
76ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes    private static Method sClipToWindowEnabledMethod;
77ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes
78ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes    static {
79ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        try {
80ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            sClipToWindowEnabledMethod = PopupWindow.class.getDeclaredMethod(
81ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes                    "setClipToScreenEnabled", boolean.class);
82ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        } catch (NoSuchMethodException e) {
83ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            Log.i(TAG, "Could not find method setClipToScreenEnabled() on PopupWindow. Oh well.");
84ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        }
85ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes    }
86ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes
873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private Context mContext;
883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private PopupWindow mPopup;
893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private ListAdapter mAdapter;
903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private DropDownListView mDropDownList;
913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mDropDownHorizontalOffset;
953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mDropDownVerticalOffset;
963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private boolean mDropDownVerticalOffsetSet;
973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private int mDropDownGravity = Gravity.NO_GRAVITY;
9949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
1003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private boolean mDropDownAlwaysVisible = false;
1013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private boolean mForceIgnoreOutsideTouch = false;
1023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    int mListItemExpandMaximum = Integer.MAX_VALUE;
1033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private View mPromptView;
1053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mPromptPosition = POSITION_PROMPT_ABOVE;
1063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private DataSetObserver mObserver;
1083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private View mDropDownAnchorView;
1103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private Drawable mDropDownListHighlight;
1123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private AdapterView.OnItemClickListener mItemClickListener;
1143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private AdapterView.OnItemSelectedListener mItemSelectedListener;
1153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
1173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
1183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private final PopupScrollListener mScrollListener = new PopupScrollListener();
1193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private final ListSelectorHider mHideSelector = new ListSelectorHider();
1203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private Runnable mShowDropDownRunnable;
1213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private Handler mHandler = new Handler();
1233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private Rect mTempRect = new Rect();
1253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private boolean mModal;
1273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int mLayoutDirection;
1293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
1313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * The provided prompt view should appear above list content.
1323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
1333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setPromptPosition(int)
1343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #getPromptPosition()
1353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setPromptView(View)
1363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int POSITION_PROMPT_ABOVE = 0;
1383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
1403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * The provided prompt view should appear below list content.
1413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
1423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setPromptPosition(int)
1433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #getPromptPosition()
1443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setPromptView(View)
1453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int POSITION_PROMPT_BELOW = 1;
1473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
14949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Alias for {@link ViewGroup.LayoutParams#MATCH_PARENT}.
15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * If used to specify a popup width, the popup will match the width of the anchor view.
15149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * If used to specify a popup height, the popup will fill available space.
1523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
15349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
1543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
15649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Alias for {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * If used to specify a popup width, the popup will use the width of its content.
1583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
1603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
16249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Mode for {@link #setInputMethodMode(int)}: the requirements for the
16349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * input method should be based on the focusability of the popup.  That is
16449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * if it is focusable than it needs to work with the input method, else
16549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * it doesn't.
1663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int INPUT_METHOD_FROM_FOCUSABLE = PopupWindow.INPUT_METHOD_FROM_FOCUSABLE;
1683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
17049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Mode for {@link #setInputMethodMode(int)}: this popup always needs to
17149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * work with an input method, regardless of whether it is focusable.  This
17249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * means that it will always be displayed so that the user can also operate
17349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the input method while it is shown.
1743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int INPUT_METHOD_NEEDED = PopupWindow.INPUT_METHOD_NEEDED;
1763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
17849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Mode for {@link #setInputMethodMode(int)}: this popup never needs to
17949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * work with an input method, regardless of whether it is focusable.  This
18049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * means that it will always be displayed to use as much space on the
18149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * screen as needed, regardless of whether this covers the input method.
1823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public static final int INPUT_METHOD_NOT_NEEDED = PopupWindow.INPUT_METHOD_NOT_NEEDED;
1843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
18649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Create a new, empty popup window capable of displaying items from a ListAdapter.
18749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
1883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
1893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param context Context used for contained views.
1903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
1913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public ListPopupWindow(Context context) {
192ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns        this(context, null, R.attr.listPopupWindowStyle);
1933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
1943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
19649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Create a new, empty popup window capable of displaying items from a ListAdapter.
19749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
1983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
1993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param context Context used for contained views.
20020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * @param attrs   Attributes from inflating parent views used to style the popup.
2013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
2023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public ListPopupWindow(Context context, AttributeSet attrs) {
203ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns        this(context, attrs, R.attr.listPopupWindowStyle);
2043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
2053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Create a new, empty popup window capable of displaying items from a ListAdapter.
20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
2093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param context Context used for contained views.
21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param attrs Attributes from inflating parent views used to style the popup.
2123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param defStyleAttr Default style attribute to use for popup content.
2133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
2143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
215a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette        this(context, attrs, defStyleAttr, 0);
216a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    }
217a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette
218a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    /**
219a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * Create a new, empty popup window capable of displaying items from a ListAdapter.
220a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
221a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     *
222a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * @param context Context used for contained views.
223a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * @param attrs Attributes from inflating parent views used to style the popup.
224a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * @param defStyleAttr Style attribute to read for default styling of popup content.
225a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     * @param defStyleRes Style resource ID to use for default styling of popup content.
226a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette     */
227a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
2283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mContext = context;
229ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes
230ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow,
231a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette                defStyleAttr, defStyleRes);
232ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        mDropDownHorizontalOffset = a.getDimensionPixelOffset(
233ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes                R.styleable.ListPopupWindow_android_dropDownHorizontalOffset, 0);
234ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        mDropDownVerticalOffset = a.getDimensionPixelOffset(
235ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes                R.styleable.ListPopupWindow_android_dropDownVerticalOffset, 0);
236ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        if (mDropDownVerticalOffset != 0) {
237ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            mDropDownVerticalOffsetSet = true;
238ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        }
239ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        a.recycle();
240ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes
2415ec2faa01bc6790bc015e0d5748dc0482ae8c0f2Chris Banes        mPopup = new AppCompatPopupWindow(context, attrs, defStyleAttr);
2423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
243469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
2443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // Set the default layout direction to match the default locale one
2453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        final Locale locale = mContext.getResources().getConfiguration().locale;
24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mLayoutDirection = TextUtilsCompat.getLayoutDirectionFromLocale(locale);
247ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns    }
2483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Sets the adapter that provides the data and the views to represent the data
25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * in this popup window.
2523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
2533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param adapter The adapter to use to create this window's content.
2543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
2553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setAdapter(ListAdapter adapter) {
2563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mObserver == null) {
2573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mObserver = new PopupDataSetObserver();
2583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        } else if (mAdapter != null) {
2593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mAdapter.unregisterDataSetObserver(mObserver);
2603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
2613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mAdapter = adapter;
2623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mAdapter != null) {
2633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            adapter.registerDataSetObserver(mObserver);
2643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
2653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mDropDownList != null) {
2673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setAdapter(mAdapter);
2683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
2693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
2703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
27249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Set where the optional prompt view should appear. The default is
27349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * {@link #POSITION_PROMPT_ABOVE}.
2743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
2753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param position A position constant declaring where the prompt should be displayed.
27649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
2773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #POSITION_PROMPT_ABOVE
2783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #POSITION_PROMPT_BELOW
2793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
2803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setPromptPosition(int position) {
2813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPromptPosition = position;
2823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
2833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
2853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return Where the optional prompt view should appear.
28649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
2873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #POSITION_PROMPT_ABOVE
2883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #POSITION_PROMPT_BELOW
2893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
2903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getPromptPosition() {
2913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPromptPosition;
2923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
2933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
2943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
2953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set whether this window should be modal when shown.
2963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
29749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>If a popup window is modal, it will receive all touch and key input.
29849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * If the user touches outside the popup window's content area the popup window
29949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * will be dismissed.
3003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param modal {@code true} if the popup window should be modal, {@code false} otherwise.
3023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setModal(boolean modal) {
304a2c72b87007d10202c25e78e904938f770c6337dChris Banes        mModal = modal;
3053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setFocusable(modal);
3063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Returns whether the popup window will be modal when shown.
3103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return {@code true} if the popup window will be modal, {@code false} otherwise.
3123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean isModal() {
3143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mModal;
3153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is
31949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we
32049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * ignore outside touch even when the drop down is not set to always visible.
3213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @hide Used only by AutoCompleteTextView to handle some internal special cases.
3233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
3253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch;
3263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets whether the drop-down should remain visible under certain conditions.
3303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
33149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * The drop-down will occupy the entire screen below {@link #getAnchorView} regardless
33249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * of the size or content of the list.  {@link #getBackground()} will fill any space
33349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * that is not used by the list.
3343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param dropDownAlwaysVisible Whether to keep the drop-down visible.
33649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
3373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @hide Only used by AutoCompleteTextView under special conditions.
3383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
3403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownAlwaysVisible = dropDownAlwaysVisible;
3413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return Whether the drop-down is visible under special conditions.
34549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
3463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @hide Only used by AutoCompleteTextView under special conditions.
3473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean isDropDownAlwaysVisible() {
3493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownAlwaysVisible;
3503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets the operating mode for the soft input area.
3543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
35549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param mode The desired mode, see
35649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *        {@link android.view.WindowManager.LayoutParams#softInputMode}
35749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *        for the full list
35849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
3593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see android.view.WindowManager.LayoutParams#softInputMode
3603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #getSoftInputMode()
3613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setSoftInputMode(int mode) {
3633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setSoftInputMode(mode);
3643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Returns the current value in {@link #setSoftInputMode(int)}.
3683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setSoftInputMode(int)
3703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see android.view.WindowManager.LayoutParams#softInputMode
3713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getSoftInputMode() {
3733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.getSoftInputMode();
3743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets a drawable to use as the list item selector.
3783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param selector List selector drawable to use in the popup.
3803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setListSelector(Drawable selector) {
3823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownListHighlight = selector;
3833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The background drawable for the popup window.
3873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public Drawable getBackground() {
3893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.getBackground();
3903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
3913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
3923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
3933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets a drawable to be the background for the popup window.
3943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
3953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param d A drawable to set as the background.
3963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
3973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setBackgroundDrawable(Drawable d) {
3983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setBackgroundDrawable(d);
3993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set an animation style to use when the popup window is shown or dismissed.
4033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param animationStyle Animation style to use.
4053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setAnimationStyle(int animationStyle) {
4073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setAnimationStyle(animationStyle);
4083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
41120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * Returns the animation style that will be used when the popup window is shown or dismissed.
4123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return Animation style that will be used.
4143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getAnimationStyle() {
4163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.getAnimationStyle();
4173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Returns the view that will be used to anchor this popup.
4213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The popup's anchor view
4233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public View getAnchorView() {
4253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownAnchorView;
4263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
42920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * Sets the popup's anchor view. This popup will always be positioned relative to the anchor
43020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns     * view when shown.
4313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param anchor The view to use as an anchor.
4333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setAnchorView(View anchor) {
4353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownAnchorView = anchor;
4363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The horizontal offset of the popup from its anchor in pixels.
4403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getHorizontalOffset() {
4423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownHorizontalOffset;
4433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set the horizontal offset of this popup from its anchor view in pixels.
4473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param offset The horizontal offset of the popup from its anchor.
4493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setHorizontalOffset(int offset) {
4513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownHorizontalOffset = offset;
4523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The vertical offset of the popup from its anchor in pixels.
4563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getVerticalOffset() {
4583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (!mDropDownVerticalOffsetSet) {
4593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return 0;
4603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
4613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownVerticalOffset;
4623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
4653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set the vertical offset of this popup from its anchor view in pixels.
4663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param offset The vertical offset of the popup from its anchor.
4683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setVerticalOffset(int offset) {
4703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownVerticalOffset = offset;
4713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownVerticalOffsetSet = true;
4723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
47549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Set the gravity of the dropdown list. This is commonly used to
47649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * set gravity to START or END for alignment with the anchor.
47749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
47849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param gravity Gravity value to use
47949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
48049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public void setDropDownGravity(int gravity) {
48149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        mDropDownGravity = gravity;
48249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
48349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
48449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
4853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The width of the popup window in pixels.
4863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getWidth() {
4883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownWidth;
4893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
4903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
4913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
49249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Sets the width of the popup window in pixels. Can also be {@link #MATCH_PARENT}
49349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * or {@link #WRAP_CONTENT}.
4943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
4953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param width Width of the popup window.
4963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
4973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setWidth(int width) {
4983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownWidth = width;
4993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
50249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Sets the width of the popup window by the size of its content. The final width may be
50349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * larger to accommodate styled window dressing.
5043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
5053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param width Desired width of content in pixels.
5063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setContentWidth(int width) {
5083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        Drawable popupBackground = mPopup.getBackground();
5093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (popupBackground != null) {
5103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            popupBackground.getPadding(mTempRect);
5113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownWidth = mTempRect.left + mTempRect.right + width;
5123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        } else {
5133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            setWidth(width);
5143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
5153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
5183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The height of the popup window in pixels.
5193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getHeight() {
5213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownHeight;
5223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
52549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}.
5263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
5273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param height Height of the popup window.
5283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setHeight(int height) {
5303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownHeight = height;
5313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
5343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets a listener to receive events when a list item is clicked.
5353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
5363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param clickListener Listener to register
53749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
5383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
5393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
5413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mItemClickListener = clickListener;
5423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
5453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Sets a listener to receive events when a list item is selected.
5463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
5473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param selectedListener Listener to register.
54849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
5493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
5503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) {
5523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mItemSelectedListener = selectedListener;
5533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
5563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set a view to act as a user prompt for this popup window. Where the prompt view will appear
5573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * is controlled by {@link #setPromptPosition(int)}.
5583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
5593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param prompt View to use as an informational prompt.
5603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setPromptView(View prompt) {
5623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        boolean showing = isShowing();
5633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (showing) {
5643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            removePromptView();
5653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
5663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPromptView = prompt;
5673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (showing) {
5683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            show();
5693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
5703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
5733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Post a {@link #show()} call to the UI thread.
5743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void postShow() {
5763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mHandler.post(mShowDropDownRunnable);
5773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
5783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
58049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Show the popup list. If the list is already showing, this method
58149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * will recalculate the popup's size and position.
5823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
5833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void show() {
5843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        int height = buildDropDown();
5853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        int widthSpec = 0;
5873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        int heightSpec = 0;
5883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        boolean noInputMethod = isInputMethodNotNeeded();
5903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
5913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mPopup.isShowing()) {
59249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
5933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // The call to PopupWindow's update method below can accept -1 for any
5943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // value you do not want to update.
5953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                widthSpec = -1;
5963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
5973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                widthSpec = getAnchorView().getWidth();
5983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else {
5993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                widthSpec = mDropDownWidth;
6003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
60249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
6033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // The call to PopupWindow's update method below can accept -1 for any
6043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // value you do not want to update.
60549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
6063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if (noInputMethod) {
6073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setWindowLayoutMode(
60849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                                    ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
6103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                } else {
6113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setWindowLayoutMode(
61249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
61349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                                    ViewGroup.LayoutParams.MATCH_PARENT : 0,
61449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            ViewGroup.LayoutParams.MATCH_PARENT);
6153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
6163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
6173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                heightSpec = height;
6183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else {
6193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                heightSpec = mDropDownHeight;
6203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
6233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
6253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mDropDownVerticalOffset, widthSpec, heightSpec);
6263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        } else {
62749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
62849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
6293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else {
6303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
6313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setWidth(getAnchorView().getWidth());
6323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                } else {
6333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setWidth(mDropDownWidth);
6343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
6353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
63749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
63849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
6393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else {
6403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
6413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setHeight(height);
6423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                } else {
6433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setHeight(mDropDownHeight);
6443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
6453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.setWindowLayoutMode(widthSpec, heightSpec);
648ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            setPopupClipToScreenEnabled(true);
6493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // use outside touchable to dismiss drop down when touching outside of it, so
6513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // only set this if the dropdown is not always visible
6523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
6533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.setTouchInterceptor(mTouchInterceptor);
65449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            PopupWindowCompat.showAsDropDown(mPopup, getAnchorView(), mDropDownHorizontalOffset,
65549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    mDropDownVerticalOffset, mDropDownGravity);
6563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setSelection(ListView.INVALID_POSITION);
6573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (!mModal || mDropDownList.isInTouchMode()) {
6593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                clearListSelection();
6603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (!mModal) {
6623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mHandler.post(mHideSelector);
6633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
6653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
6663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
6683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Dismiss the popup window.
6693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
6703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void dismiss() {
6713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.dismiss();
6723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        removePromptView();
6733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setContentView(null);
6743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mDropDownList = null;
6753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mHandler.removeCallbacks(mResizePopupRunnable);
6763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
6773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
6793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Set a listener to receive a callback when the popup is dismissed.
6803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
6813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param listener Listener that will be notified when the popup is dismissed.
6823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
6833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
6843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setOnDismissListener(listener);
6853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
6863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private void removePromptView() {
6883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mPromptView != null) {
6893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            final ViewParent parent = mPromptView.getParent();
6903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (parent instanceof ViewGroup) {
6913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final ViewGroup group = (ViewGroup) parent;
6923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                group.removeView(mPromptView);
6933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
6943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
6953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
6963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
6973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
69849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Control how the popup operates with an input method: one of
69949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
70049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * or {@link #INPUT_METHOD_NOT_NEEDED}.
7013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
70249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>If the popup is showing, calling this method will take effect only
70349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the next time the popup is shown or through a manual call to the {@link #show()}
70449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * method.</p>
7053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
7063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #getInputMethodMode()
7073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #show()
7083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setInputMethodMode(int mode) {
7103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mPopup.setInputMethodMode(mode);
7113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
7143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Return the current value in {@link #setInputMethodMode(int)}.
7153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
7163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setInputMethodMode(int)
7173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getInputMethodMode() {
7193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.getInputMethodMode();
7203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
72349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Set the selected position of the list.
72449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Only valid when {@link #isShowing()} == {@code true}.
7253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
7263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param position List position to set as selected.
7273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void setSelection(int position) {
7293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        DropDownListView list = mDropDownList;
7303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (isShowing() && list != null) {
7313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            list.mListSelectionHidden = false;
7323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            list.setSelection(position);
73349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
73449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (Build.VERSION.SDK_INT >= 11) {
73549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
73649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    list.setItemChecked(position, true);
73749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
7383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
7393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
7403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
74349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Clear any current list selection.
74449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Only valid when {@link #isShowing()} == {@code true}.
7453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public void clearListSelection() {
7473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        final DropDownListView list = mDropDownList;
7483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (list != null) {
7493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // WARNING: Please read the comment where mListSelectionHidden is declared
7503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            list.mListSelectionHidden = true;
7513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            //list.hideSelector();
7523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            list.requestLayout();
7533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
7543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
7573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return {@code true} if the popup is currently showing, {@code false} otherwise.
7583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean isShowing() {
7603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.isShowing();
7613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
76449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return {@code true} if this popup is configured to assume the user does not need
76549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * to interact with the IME while it is showing, {@code false} otherwise.
7663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean isInputMethodNotNeeded() {
7683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mPopup.getInputMethodMode() == INPUT_METHOD_NOT_NEEDED;
7693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
7723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * Perform an item click operation on the specified list adapter position.
7733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
7743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param position Adapter position for performing the click
77549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return true if the click action could be performed, false if not.
77649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *         (e.g. if the popup was not showing, this method would return false.)
7773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean performItemClick(int position) {
7793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (isShowing()) {
7803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (mItemClickListener != null) {
7813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final DropDownListView list = mDropDownList;
7823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final View child = list.getChildAt(position - list.getFirstVisiblePosition());
7833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final ListAdapter adapter = list.getAdapter();
7843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mItemClickListener.onItemClick(list, child, position, adapter.getItemId(position));
7853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
7863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return true;
7873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
7883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return false;
7893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
7903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
7913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
7923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return The currently selected item or null if the popup is not showing.
7933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
7943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public Object getSelectedItem() {
7953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (!isShowing()) {
7963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return null;
7973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
7983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownList.getSelectedItem();
7993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
80249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return The position of the currently selected item or {@link ListView#INVALID_POSITION}
80349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * if {@link #isShowing()} == {@code false}.
80449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
8053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see ListView#getSelectedItemPosition()
8063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public int getSelectedItemPosition() {
8083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (!isShowing()) {
8093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return ListView.INVALID_POSITION;
8103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
8113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownList.getSelectedItemPosition();
8123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
81549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return The ID of the currently selected item or {@link ListView#INVALID_ROW_ID}
81649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * if {@link #isShowing()} == {@code false}.
81749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
8183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see ListView#getSelectedItemId()
8193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public long getSelectedItemId() {
8213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (!isShowing()) {
8223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return ListView.INVALID_ROW_ID;
8233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
8243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownList.getSelectedItemId();
8253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
82849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return The View for the currently selected item or null if
82949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * {@link #isShowing()} == {@code false}.
83049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
8313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see ListView#getSelectedView()
8323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public View getSelectedView() {
8343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (!isShowing()) {
8353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return null;
8363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
8373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownList.getSelectedView();
8383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
84149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return The {@link ListView} displayed within the popup window.
84249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Only valid when {@link #isShowing()} == {@code true}.
8433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public ListView getListView() {
8453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return mDropDownList;
8463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
84949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * The maximum number of list items that can be visible and still have
85049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the list expand when touched.
8513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
8523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param max Max number of items that can be visible and still allow the list to expand.
8533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    void setListItemExpandMax(int max) {
8553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        mListItemExpandMaximum = max;
8563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
8573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
85949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Filter key down events. By forwarding key down events to this function,
86049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * views using non-modal ListPopupWindow can have it handle key selection of items.
8613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
8623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param keyCode keyCode param passed to the host view's onKeyDown
86349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param event event param passed to the host view's onKeyDown
8643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return true if the event was handled, false if it was ignored.
86549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
8663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setModal(boolean)
8673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
8683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean onKeyDown(int keyCode, KeyEvent event) {
8693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // when the drop down is shown, we drive it directly
8703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (isShowing()) {
8713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // the key events are forwarded to the list in the drop down view
8723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // note that ListView handles space but we don't want that to happen
8733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // also if selection is not currently in the drop down, then don't
8743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // let center or enter presses go there since that would cause it
8753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // to select one of its items
8763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (keyCode != KeyEvent.KEYCODE_SPACE
8773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    && (mDropDownList.getSelectedItemPosition() >= 0
87849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    || !isConfirmKey(keyCode))) {
8793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                int curIndex = mDropDownList.getSelectedItemPosition();
8803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                boolean consumed;
8813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final boolean below = !mPopup.isAboveAnchor();
8833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                final ListAdapter adapter = mAdapter;
8853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                boolean allEnabled;
8873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                int firstItem = Integer.MAX_VALUE;
8883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                int lastItem = Integer.MIN_VALUE;
8893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if (adapter != null) {
8913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    allEnabled = adapter.areAllItemsEnabled();
8923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    firstItem = allEnabled ? 0 :
893ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns                            mDropDownList.lookForSelectablePosition(0, true);
8943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    lastItem = allEnabled ? adapter.getCount() - 1 :
895ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns                            mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
8963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
8973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
8983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= firstItem) ||
8993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        (!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >= lastItem)) {
9003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // When the selection is at the top, we block the key
9013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // event to prevent focus from moving.
9023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    clearListSelection();
9033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
9043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    show();
9053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    return true;
9063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                } else {
9073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // WARNING: Please read the comment where mListSelectionHidden
9083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    //          is declared
9093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mDropDownList.mListSelectionHidden = false;
9103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
9113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                consumed = mDropDownList.onKeyDown(keyCode, event);
91349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + consumed);
9143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                if (consumed) {
9163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // If it handled the key event, then the user is
9173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // navigating in the list, so we should put it in front.
9183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
9193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // Here's a little trick we need to do to make sure that
9203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // the list view is actually showing its focus indicator,
9213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // by ensuring it has focus and getting its window out
9223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // of touch mode.
9233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mDropDownList.requestFocusFromTouch();
9243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    show();
9253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    switch (keyCode) {
9273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        // avoid passing the focus from the text view to the
9283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        // next component
9293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        case KeyEvent.KEYCODE_ENTER:
9303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        case KeyEvent.KEYCODE_DPAD_CENTER:
9313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        case KeyEvent.KEYCODE_DPAD_DOWN:
9323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        case KeyEvent.KEYCODE_DPAD_UP:
9333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                            return true;
9343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
9353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                } else {
9363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    if (below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
9373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        // when the selection is at the bottom, we block the
9383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        // event to avoid going to the next focusable widget
9393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        if (curIndex == lastItem) {
9403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                            return true;
9413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        }
9423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    } else if (!below && keyCode == KeyEvent.KEYCODE_DPAD_UP &&
9433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                            curIndex == firstItem) {
9443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        return true;
9453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
9463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
9473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
9483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
9493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return false;
9513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
9523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
95449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Filter key down events. By forwarding key up events to this function,
95549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * views using non-modal ListPopupWindow can have it handle key selection of items.
9563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
9573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @param keyCode keyCode param passed to the host view's onKeyUp
95849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param event event param passed to the host view's onKeyUp
9593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return true if the event was handled, false if it was ignored.
96049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
9613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @see #setModal(boolean)
9623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
9633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    public boolean onKeyUp(int keyCode, KeyEvent event) {
9643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
9653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            boolean consumed = mDropDownList.onKeyUp(keyCode, event);
96649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (consumed && isConfirmKey(keyCode)) {
96749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                // if the list accepts the key events and the key event was a click, the text view
96849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                // gets the selected item from the drop down as its content
96949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                dismiss();
9703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
9713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return consumed;
9723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
9733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return false;
9743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
9753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
9763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
97749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Filter pre-IME key events. By forwarding {@link View#onKeyPreIme(int, KeyEvent)}
97849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * events to this function, views using ListPopupWindow can have it dismiss the popup
97949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * when the back key is pressed.
98049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
98149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param keyCode keyCode param passed to the host view's onKeyPreIme
98249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param event event param passed to the host view's onKeyPreIme
98349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return true if the event was handled, false if it was ignored.
98449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
98549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @see #setModal(boolean)
98649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
98749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
98849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
98949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // special case for the back key, we do not even try to send it
99049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // to the drop down list but instead, consume it immediately
99149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final View anchorView = mDropDownAnchorView;
99249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
99349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
99449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (state != null) {
99549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    state.startTracking(event, this);
99649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
99749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return true;
99849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else if (event.getAction() == KeyEvent.ACTION_UP) {
99949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
100049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (state != null) {
100149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    state.handleUpEvent(event);
100249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
100349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (event.isTracking() && !event.isCanceled()) {
100449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    dismiss();
100549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    return true;
100649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
100749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
100849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
100949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return false;
101049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
101149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
101249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
101349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Returns an {@link OnTouchListener} that can be added to the source view
101449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * to implement drag-to-open behavior. Generally, the source view should be
101549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * the same view that was passed to {@link #setAnchorView}.
101649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>
101749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * When the listener is set on a view, touching that view and dragging
101849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * outside of its bounds will open the popup window. Lifting will select the
101949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * currently touched list item.
102049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>
102149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Example usage:
102249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <pre>
102349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * ListPopupWindow myPopup = new ListPopupWindow(context);
102449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * myPopup.setAnchor(myAnchor);
102549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * OnTouchListener dragListener = myPopup.createDragToOpenListener(myAnchor);
102649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * myAnchor.setOnTouchListener(dragListener);
102749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * </pre>
102849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     *
102949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @param src the view on which the resulting listener will be set
103049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @return a touch listener that controls drag-to-open behavior
103149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
103249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    public OnTouchListener createDragToOpenListener(View src) {
103349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return new ForwardingListener(src) {
103449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            @Override
103549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            public ListPopupWindow getPopup() {
103649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return ListPopupWindow.this;
103749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
103849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        };
103949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
104049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
104149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    /**
104249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>Builds the popup window's content and returns the height the popup
104349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * should have. Returns -1 when the content already exists.</p>
10443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
10453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     * @return the content's height or -1 if content already exists
10463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
10473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private int buildDropDown() {
10483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        ViewGroup dropDownView;
10493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        int otherHeights = 0;
10503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (mDropDownList == null) {
10523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            Context context = mContext;
10533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            /**
10553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani             * This Runnable exists for the sole purpose of checking if the view layout has got
10563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani             * completed and if so call showDropDown to display the drop down. This is used to show
10573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani             * the drop down as soon as possible after user opens up the search dialog, without
10583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani             * waiting for the normal UI pipeline to do it's job which is slower than this method.
10593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani             */
10603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mShowDropDownRunnable = new Runnable() {
10613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                public void run() {
10623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    // View layout should be all done before displaying the drop down.
10633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    View view = getAnchorView();
10643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    if (view != null && view.getWindowToken() != null) {
10653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        show();
10663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
10673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
10683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            };
10693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList = new DropDownListView(context, !mModal);
10713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (mDropDownListHighlight != null) {
10723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mDropDownList.setSelector(mDropDownListHighlight);
10733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
10743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setAdapter(mAdapter);
10753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setOnItemClickListener(mItemClickListener);
10763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setFocusable(true);
10773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setFocusableInTouchMode(true);
10783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
10793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                public void onItemSelected(AdapterView<?> parent, View view,
108020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                        int position, long id) {
10813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    if (position != -1) {
10833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        DropDownListView dropDownList = mDropDownList;
10843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        if (dropDownList != null) {
10863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                            dropDownList.mListSelectionHidden = false;
10873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        }
10883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
10893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
10903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                public void onNothingSelected(AdapterView<?> parent) {
10923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
10933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            });
10943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mDropDownList.setOnScrollListener(mScrollListener);
10953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
10963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (mItemSelectedListener != null) {
10973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
10983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
10993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            dropDownView = mDropDownList;
11013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            View hintView = mPromptView;
11033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (hintView != null) {
11043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // if a hint has been specified, we accomodate more space for it and
11053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // add a text view in the drop down menu, at the bottom of the list
11063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                LinearLayout hintContainer = new LinearLayout(context);
11073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                hintContainer.setOrientation(LinearLayout.VERTICAL);
11083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
111049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
11113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                );
11123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                switch (mPromptPosition) {
11143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    case POSITION_PROMPT_BELOW:
11153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        hintContainer.addView(dropDownView, hintParams);
11163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        hintContainer.addView(hintView);
11173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        break;
11183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    case POSITION_PROMPT_ABOVE:
11203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        hintContainer.addView(hintView);
11213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        hintContainer.addView(dropDownView, hintParams);
11223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        break;
11233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    default:
11253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        Log.e(TAG, "Invalid hint position " + mPromptPosition);
11263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        break;
11273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
11283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // measure the hint's height to find how much more vertical space
11303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // we need to add to the drop down's height
11313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
11323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                int heightSpec = MeasureSpec.UNSPECIFIED;
11333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                hintView.measure(widthSpec, heightSpec);
11343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
11363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
11373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        + hintParams.bottomMargin;
11383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                dropDownView = hintContainer;
11403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
11413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mPopup.setContentView(dropDownView);
11433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        } else {
11443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            dropDownView = (ViewGroup) mPopup.getContentView();
11453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            final View view = mPromptView;
11463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (view != null) {
11473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                LinearLayout.LayoutParams hintParams =
11483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        (LinearLayout.LayoutParams) view.getLayoutParams();
11493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                otherHeights = view.getMeasuredHeight() + hintParams.topMargin
11503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        + hintParams.bottomMargin;
11513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
11523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
11533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // getMaxAvailableHeight() subtracts the padding, so we put it back
11553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // to get the available height for the whole window
11563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        int padding = 0;
11573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        Drawable background = mPopup.getBackground();
11583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        if (background != null) {
11593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            background.getPadding(mTempRect);
11603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            padding = mTempRect.top + mTempRect.bottom;
11613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // If we don't have an explicit vertical offset, determine one from the window
11633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // background so that content will line up.
11643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (!mDropDownVerticalOffsetSet) {
11653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mDropDownVerticalOffset = -mTempRect.top;
11663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
11673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        } else {
11683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mTempRect.setEmpty();
11693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
11703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // Max height available on the screen for a popup.
11723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        boolean ignoreBottomDecorations =
11733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
117449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        final int maxHeight = mPopup.getMaxAvailableHeight(
117549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                getAnchorView(), mDropDownVerticalOffset /*, ignoreBottomDecorations*/);
11763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
1177a2c72b87007d10202c25e78e904938f770c6337dChris Banes        if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
11783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return maxHeight + padding;
11793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
11803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
11813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        final int childWidthSpec;
11823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        switch (mDropDownWidth) {
11833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            case ViewGroup.LayoutParams.WRAP_CONTENT:
11843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                childWidthSpec = MeasureSpec.makeMeasureSpec(
11853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        mContext.getResources().getDisplayMetrics().widthPixels -
11863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                                (mTempRect.left + mTempRect.right),
11873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        MeasureSpec.AT_MOST);
11883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                break;
1189a2c72b87007d10202c25e78e904938f770c6337dChris Banes            case ViewGroup.LayoutParams.MATCH_PARENT:
11903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                childWidthSpec = MeasureSpec.makeMeasureSpec(
11913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        mContext.getResources().getDisplayMetrics().widthPixels -
11923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                                (mTempRect.left + mTempRect.right),
11933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                        MeasureSpec.EXACTLY);
11943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                break;
11953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            default:
11963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                childWidthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.EXACTLY);
11973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                break;
11983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
1199ba2e44b17a9ed3d39d05b52f9764165e063f5386Trevor Johns
120079e7a9ef79920c7daa10c90339db126a4c3c592eChris Banes        final int listContent = mDropDownList.measureHeightOfChildrenCompat(childWidthSpec,
12013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                0, DropDownListView.NO_POSITION, maxHeight - otherHeights, -1);
12023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // add padding only if the list has items in it, that way we don't show
12033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        // the popup if it is not needed
1204ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        if (listContent > 0) otherHeights += padding;
12053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
12063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        return listContent + otherHeights;
12073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
12083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
12093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
121049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * Abstract class that forwards touch events to a {@link ListPopupWindow}.
12113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     *
121249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * @hide
121349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     */
1214a2c72b87007d10202c25e78e904938f770c6337dChris Banes    public static abstract class ForwardingListener implements View.OnTouchListener {
121549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Scaled touch slop, used for detecting movement outside bounds. */
121649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private final float mScaledTouchSlop;
121749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
121849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Timeout before disallowing intercept on the source's parent. */
121949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private final int mTapTimeout;
1220a2c72b87007d10202c25e78e904938f770c6337dChris Banes        /** Timeout before accepting a long-press to start forwarding. */
1221a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private final int mLongPressTimeout;
122249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
122349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Source view from which events are forwarded. */
122449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private final View mSrc;
122549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
122649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Runnable used to prevent conflicts with scrolling parents. */
122749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private Runnable mDisallowIntercept;
1228a2c72b87007d10202c25e78e904938f770c6337dChris Banes        /** Runnable used to trigger forwarding on long-press. */
1229a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private Runnable mTriggerLongPress;
123049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
123149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Whether this listener is currently forwarding touch events. */
123249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean mForwarding;
1233a2c72b87007d10202c25e78e904938f770c6337dChris Banes        /**
1234a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * Whether forwarding was initiated by a long-press. If so, we won't
1235a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * force the window to dismiss when the touch stream ends.
1236a2c72b87007d10202c25e78e904938f770c6337dChris Banes         */
1237a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private boolean mWasLongPress;
123849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
123949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** The id of the first pointer down in the current event stream. */
124049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private int mActivePointerId;
124149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
124249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
124349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Temporary Matrix instance
124449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
124549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private final int[] mTmpLocation = new int[2];
124649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
124749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public ForwardingListener(View src) {
124849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mSrc = src;
124949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
125049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mTapTimeout = ViewConfiguration.getTapTimeout();
1251a2c72b87007d10202c25e78e904938f770c6337dChris Banes            // Use a medium-press timeout. Halfway between tap and long-press.
1252a2c72b87007d10202c25e78e904938f770c6337dChris Banes            mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
125349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
125449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
125549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
1256a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * Returns the popup to which this listener is forwarding events.
1257a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * <p>
1258a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * Override this to return the correct popup. If the popup is displayed
1259a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * asynchronously, you may also need to override
1260a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * {@link #onForwardingStopped} to prevent premature cancelation of
1261a2c72b87007d10202c25e78e904938f770c6337dChris Banes         * forwarding.
126249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
126349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return the popup to which this listener is forwarding events
126449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
126549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public abstract ListPopupWindow getPopup();
126649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
126749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
126849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onTouch(View v, MotionEvent event) {
126949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final boolean wasForwarding = mForwarding;
127049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final boolean forwarding;
127149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (wasForwarding) {
1272a2c72b87007d10202c25e78e904938f770c6337dChris Banes                if (mWasLongPress) {
1273a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    // If we started forwarding as a result of a long-press,
1274a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    // just silently stop forwarding events so that the window
1275a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    // stays open.
1276a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    forwarding = onTouchForwarded(event);
1277a2c72b87007d10202c25e78e904938f770c6337dChris Banes                } else {
1278a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    forwarding = onTouchForwarded(event) || !onForwardingStopped();
1279a2c72b87007d10202c25e78e904938f770c6337dChris Banes                }
128049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else {
128149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                forwarding = onTouchObserved(event) && onForwardingStarted();
128249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
128349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (forwarding) {
128449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    // Make sure we cancel any ongoing source event stream.
128549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final long now = SystemClock.uptimeMillis();
128649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
128749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            0.0f, 0.0f, 0);
128849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    mSrc.onTouchEvent(e);
128949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    e.recycle();
129049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                }
129149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
129249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
129349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mForwarding = forwarding;
129449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return forwarding || wasForwarding;
129549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
129649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
129749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
129849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Called when forwarding would like to start. <p> By default, this will show the popup
129949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * returned by {@link #getPopup()}. It may be overridden to perform another action, like
130049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * clicking the source view or preparing the popup before showing it.
130149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
130249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return true to start forwarding, false otherwise
130349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
130449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        protected boolean onForwardingStarted() {
130549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final ListPopupWindow popup = getPopup();
130649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (popup != null && !popup.isShowing()) {
130749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                popup.show();
130849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
130949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return true;
131049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
131149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
131249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
131349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Called when forwarding would like to stop. <p> By default, this will dismiss the popup
131449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * returned by {@link #getPopup()}. It may be overridden to perform some other action.
131549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
131649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return true to stop forwarding, false otherwise
131749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
131849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        protected boolean onForwardingStopped() {
131949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final ListPopupWindow popup = getPopup();
132049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (popup != null && popup.isShowing()) {
132149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                popup.dismiss();
132249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
132349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return true;
132449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
132549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
132649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
132749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Observes motion events and determines when to start forwarding.
132849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
132949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @param srcEvent motion event in source view coordinates
133049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return true to start forwarding motion events, false otherwise
133149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
133249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean onTouchObserved(MotionEvent srcEvent) {
133349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final View src = mSrc;
133449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (!src.isEnabled()) {
133549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return false;
133649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
133749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
133849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int actionMasked = MotionEventCompat.getActionMasked(srcEvent);
133949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            switch (actionMasked) {
134049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_DOWN:
134149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    mActivePointerId = srcEvent.getPointerId(0);
1342a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    mWasLongPress = false;
1343a2c72b87007d10202c25e78e904938f770c6337dChris Banes
134449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (mDisallowIntercept == null) {
134549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        mDisallowIntercept = new DisallowIntercept();
134649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    }
134749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    src.postDelayed(mDisallowIntercept, mTapTimeout);
1348a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    if (mTriggerLongPress == null) {
1349a2c72b87007d10202c25e78e904938f770c6337dChris Banes                        mTriggerLongPress = new TriggerLongPress();
1350a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    }
1351a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    src.postDelayed(mTriggerLongPress, mLongPressTimeout);
135249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    break;
135349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_MOVE:
135449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
135549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (activePointerIndex >= 0) {
135649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        final float x = srcEvent.getX(activePointerIndex);
135749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        final float y = srcEvent.getY(activePointerIndex);
135849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        if (!pointInView(src, x, y, mScaledTouchSlop)) {
1359a2c72b87007d10202c25e78e904938f770c6337dChris Banes                            clearCallbacks();
1360a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1361a2c72b87007d10202c25e78e904938f770c6337dChris Banes                            // Don't let the parent intercept our events.
136249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            src.getParent().requestDisallowInterceptTouchEvent(true);
136349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                            return true;
136449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        }
136549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    }
136649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    break;
136749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_CANCEL:
136849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_UP:
1369a2c72b87007d10202c25e78e904938f770c6337dChris Banes                    clearCallbacks();
137049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    break;
137149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
137249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
137349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return false;
13743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
137549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
1376a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private void clearCallbacks() {
1377a2c72b87007d10202c25e78e904938f770c6337dChris Banes            if (mTriggerLongPress != null) {
1378a2c72b87007d10202c25e78e904938f770c6337dChris Banes                mSrc.removeCallbacks(mTriggerLongPress);
1379a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
1380a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1381a2c72b87007d10202c25e78e904938f770c6337dChris Banes            if (mDisallowIntercept != null) {
1382a2c72b87007d10202c25e78e904938f770c6337dChris Banes                mSrc.removeCallbacks(mDisallowIntercept);
1383a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
1384a2c72b87007d10202c25e78e904938f770c6337dChris Banes        }
1385a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1386a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private void onLongPress() {
1387a2c72b87007d10202c25e78e904938f770c6337dChris Banes            clearCallbacks();
1388a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1389a2c72b87007d10202c25e78e904938f770c6337dChris Banes            final View src = mSrc;
1390a2c72b87007d10202c25e78e904938f770c6337dChris Banes            if (!src.isEnabled()) {
1391a2c72b87007d10202c25e78e904938f770c6337dChris Banes                return;
1392a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
1393a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1394a2c72b87007d10202c25e78e904938f770c6337dChris Banes            if (!onForwardingStarted()) {
1395a2c72b87007d10202c25e78e904938f770c6337dChris Banes                return;
1396a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
1397a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1398a2c72b87007d10202c25e78e904938f770c6337dChris Banes            // Don't let the parent intercept our events.
1399a2c72b87007d10202c25e78e904938f770c6337dChris Banes            mSrc.getParent().requestDisallowInterceptTouchEvent(true);
1400a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1401a2c72b87007d10202c25e78e904938f770c6337dChris Banes            // Make sure we cancel any ongoing source event stream.
1402a2c72b87007d10202c25e78e904938f770c6337dChris Banes            final long now = SystemClock.uptimeMillis();
1403a2c72b87007d10202c25e78e904938f770c6337dChris Banes            final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
1404a2c72b87007d10202c25e78e904938f770c6337dChris Banes            mSrc.onTouchEvent(e);
1405a2c72b87007d10202c25e78e904938f770c6337dChris Banes            e.recycle();
1406a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1407a2c72b87007d10202c25e78e904938f770c6337dChris Banes            mForwarding = true;
1408a2c72b87007d10202c25e78e904938f770c6337dChris Banes            mWasLongPress = true;
1409a2c72b87007d10202c25e78e904938f770c6337dChris Banes        }
1410a2c72b87007d10202c25e78e904938f770c6337dChris Banes
141149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
141249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Handled forwarded motion events and determines when to stop forwarding.
141349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         *
141449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @param srcEvent motion event in source view coordinates
141549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return true to continue forwarding motion events, false to cancel
141649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
141749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean onTouchForwarded(MotionEvent srcEvent) {
141849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final View src = mSrc;
141949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final ListPopupWindow popup = getPopup();
142049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (popup == null || !popup.isShowing()) {
142149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return false;
142249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
142349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
142449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final DropDownListView dst = popup.mDropDownList;
142549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (dst == null || !dst.isShown()) {
142649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                return false;
142749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
142849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
142949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Convert event to destination-local coordinates.
143049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
143149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            toGlobalMotionEvent(src, dstEvent);
143249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            toLocalMotionEvent(dst, dstEvent);
143349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
143449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Forward converted event to destination view, then recycle it.
143549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
143649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            dstEvent.recycle();
143749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
143849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Always cancel forwarding when the touch stream ends.
143949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int action = MotionEventCompat.getActionMasked(srcEvent);
144049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final boolean keepForwarding = action != MotionEvent.ACTION_UP
144149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    && action != MotionEvent.ACTION_CANCEL;
144249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
144349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return handled && keepForwarding;
144449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
144549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
144649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private static boolean pointInView(View view, float localX, float localY, float slop) {
144749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return localX >= -slop && localY >= -slop &&
144849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    localX < ((view.getRight() - view.getLeft()) + slop) &&
144949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    localY < ((view.getBottom() - view.getTop()) + slop);
145049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
145149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
145249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
145349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Emulates View.toLocalMotionEvent(). This implementation does not handle transformations
145449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * (scaleX, scaleY, etc).
145549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
145649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean toLocalMotionEvent(View view, MotionEvent event) {
145749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int[] loc = mTmpLocation;
145849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            view.getLocationOnScreen(loc);
145949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            event.offsetLocation(-loc[0], -loc[1]);
146049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return true;
14613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
14623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
146349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
146449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Emulates View.toGlobalMotionEvent(). This implementation does not handle transformations
146549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * (scaleX, scaleY, etc).
146649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
146749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean toGlobalMotionEvent(View view, MotionEvent event) {
146849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int[] loc = mTmpLocation;
146949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            view.getLocationOnScreen(loc);
147049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            event.offsetLocation(loc[0], loc[1]);
147149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return true;
147249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
147349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
147449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private class DisallowIntercept implements Runnable {
147549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            @Override
147649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            public void run() {
147749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                final ViewParent parent = mSrc.getParent();
147849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                parent.requestDisallowInterceptTouchEvent(true);
147949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
148049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
1481a2c72b87007d10202c25e78e904938f770c6337dChris Banes
1482a2c72b87007d10202c25e78e904938f770c6337dChris Banes        private class TriggerLongPress implements Runnable {
1483a2c72b87007d10202c25e78e904938f770c6337dChris Banes            @Override
1484a2c72b87007d10202c25e78e904938f770c6337dChris Banes            public void run() {
1485a2c72b87007d10202c25e78e904938f770c6337dChris Banes                onLongPress();
1486a2c72b87007d10202c25e78e904938f770c6337dChris Banes            }
1487a2c72b87007d10202c25e78e904938f770c6337dChris Banes        }
14883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
14893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
14903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    /**
149149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
149249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * make sure the list uses the appropriate drawables and states when
149349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * displayed on screen within a drop down. The focus is never actually
149449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes     * passed to the drop down in this mode; the list only looks focused.</p>
14953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani     */
149649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private static class DropDownListView extends ListViewCompat {
149720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns
14983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /*
149920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * WARNING: This is a workaround for a touch mode issue.
150020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *
150120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * Touch mode is propagated lazily to windows. This causes problems in
150220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * the following scenario:
150320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * - Type something in the AutoCompleteTextView and get some results
150420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * - Move down with the d-pad to select an item in the list
150520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * - Move up with the d-pad until the selection disappears
150620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * - Type more text in the AutoCompleteTextView *using the soft keyboard*
150720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *   and get new results; you are now in touch mode
150820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * - The selection comes back on the first item in the list, even though
150920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *   the list is supposed to be in touch mode
151020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *
151120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * Using the soft keyboard triggers the touch mode change but that change
151220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * is propagated to our window only after the first list layout, therefore
151320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * after the list attempts to resurrect the selection.
151420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *
151520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * The trick to work around this issue is to pretend the list is in touch
151620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * mode when we know that the selection should not appear, that is when
151720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * we know the user moved the selection away from the list.
151820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *
151920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * This boolean is set to true whenever we explicitly hide the list's
152020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * selection and reset to false whenever we know the user moved the
152120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * selection back to the list.
152220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        *
152320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * When this boolean is true, isInTouchMode() returns true, otherwise it
152420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        * returns super.isInTouchMode().
152520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns        */
15263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        private boolean mListSelectionHidden;
15273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
15283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
15293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * True if this wrapper should fake focus.
15303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
15313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        private boolean mHijackFocus;
15323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
153349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Whether to force drawing of the pressed state selector. */
153449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private boolean mDrawsInPressedState;
153549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
153649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Current drag-to-open click animation, if any. */
153749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private ViewPropertyAnimatorCompat mClickAnimation;
153849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
153949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /** Helper for drag-to-open auto scrolling. */
154049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private ListViewAutoScrollHelper mScrollHelper;
154149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
15423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
15433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * <p>Creates a new list view wrapper.</p>
15443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         *
15453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * @param context this view's context
15463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
15473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public DropDownListView(Context context, boolean hijackFocus) {
15483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            super(context, null, R.attr.dropDownListViewStyle);
15493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            mHijackFocus = hijackFocus;
15503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            setCacheColorHint(0); // Transparent, since the background drawable could be anything.
15513565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
15523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
15533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
155449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Handles forwarded events.
15553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         *
155649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @param activePointerId id of the pointer that activated forwarding
155749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * @return whether the event was handled
15583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
155949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
156049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            boolean handledEvent = true;
156149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            boolean clearPressedItem = false;
156249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
156349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final int actionMasked = MotionEventCompat.getActionMasked(event);
156449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            switch (actionMasked) {
156549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_CANCEL:
156649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    handledEvent = false;
156749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    break;
156849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_UP:
156949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    handledEvent = false;
157049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    // $FALL-THROUGH$
157149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                case MotionEvent.ACTION_MOVE:
157249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final int activeIndex = event.findPointerIndex(activePointerId);
157349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (activeIndex < 0) {
157449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        handledEvent = false;
157549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        break;
157649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    }
15773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
157849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final int x = (int) event.getX(activeIndex);
157949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final int y = (int) event.getY(activeIndex);
158049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final int position = pointToPosition(x, y);
158149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (position == INVALID_POSITION) {
158249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        clearPressedItem = true;
158349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        break;
15843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
158549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
158649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    final View child = getChildAt(position - getFirstVisiblePosition());
158749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    setPressedItem(child, position, x, y);
158849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    handledEvent = true;
158949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
159049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    if (actionMasked == MotionEvent.ACTION_UP) {
159149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                        clickPressedItem(child, position);
15923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    }
159349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    break;
159449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
15953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
159649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Failure to handle the event cancels forwarding.
159749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (!handledEvent || clearPressedItem) {
159849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                clearPressedItem();
159949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
160049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
160149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Manage automatic scrolling.
160249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (handledEvent) {
160349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                if (mScrollHelper == null) {
160449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                    mScrollHelper = new ListViewAutoScrollHelper(this);
16053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                }
160649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                mScrollHelper.setEnabled(true);
160749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                mScrollHelper.onTouch(this, event);
160849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            } else if (mScrollHelper != null) {
160949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                mScrollHelper.setEnabled(false);
161049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            }
161149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
161249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return handledEvent;
161349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
161449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
161549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        /**
161649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * Starts an alpha animation on the selector. When the animation ends,
161749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         * the list performs a click on the item.
161849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes         */
161949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private void clickPressedItem(final View child, final int position) {
162049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            final long id = getItemIdAtPosition(position);
162149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            performItemClick(child, position, id);
162249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
162349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
162449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private void clearPressedItem() {
162549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mDrawsInPressedState = false;
162649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            setPressed(false);
162749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // This will call through to updateSelectorState()
162849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            drawableStateChanged();
162949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
163049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            if (mClickAnimation != null) {
163149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                mClickAnimation.cancel();
163249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes                mClickAnimation = null;
16333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
16343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
16353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
163649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        private void setPressedItem(View child, int position, float x, float y) {
163749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            mDrawsInPressedState = true;
163849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
163949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Ordering is essential. First update the pressed state and layout
164049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // the children. This will ensure the selector actually gets drawn.
164149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            setPressed(true);
164249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            layoutChildren();
164349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
164449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Ensure that keyboard focus starts from the last touched position.
164549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            setSelection(position);
164649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            positionSelectorLikeTouchCompat(position, child, x, y);
164749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
164880e66c1609421dacff3e49770411e201039aa1d8Chris Banes            // This needs some explanation. We need to disable the selector for this next call
164980e66c1609421dacff3e49770411e201039aa1d8Chris Banes            // due to the way that ListViewCompat works. Otherwise both ListView and ListViewCompat
165080e66c1609421dacff3e49770411e201039aa1d8Chris Banes            // will draw the selector and bad things happen.
165180e66c1609421dacff3e49770411e201039aa1d8Chris Banes            setSelectorEnabled(false);
165280e66c1609421dacff3e49770411e201039aa1d8Chris Banes
165349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // Refresh the drawable state to reflect the new pressed state,
165449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            // which will also update the selector state.
165549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            refreshDrawableState();
165649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
165749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
165849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        @Override
165949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        protected boolean touchModeDrawsInPressedStateCompat() {
166049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes            return mDrawsInPressedState || super.touchModeDrawsInPressedStateCompat();
166149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        }
166249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
16633565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
16643565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public boolean isInTouchMode() {
16653565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            // WARNING: Please read the comment where mListSelectionHidden is declared
16663565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
16673565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
16683565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
16693565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
16703565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * <p>Returns the focus state in the drop down.</p>
16713565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         *
16723565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * @return true always if hijacking focus
16733565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
16743565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
16753565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public boolean hasWindowFocus() {
16763565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return mHijackFocus || super.hasWindowFocus();
16773565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
16783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
16793565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
16803565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * <p>Returns the focus state in the drop down.</p>
16813565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         *
16823565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * @return true always if hijacking focus
16833565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
16843565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
16853565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public boolean isFocused() {
16863565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return mHijackFocus || super.isFocused();
16873565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
16883565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
16893565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        /**
16903565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * <p>Returns the focus state in the drop down.</p>
16913565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         *
16923565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         * @return true always if hijacking focus
16933565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani         */
16943565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
16953565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public boolean hasFocus() {
16963565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return mHijackFocus || super.hasFocus();
16973565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
16983565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
16993565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
17003565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17013565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private class PopupDataSetObserver extends DataSetObserver {
17023565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
17033565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void onChanged() {
17043565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (isShowing()) {
17053565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                // Resize the popup to fit new content
17063565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                show();
17073565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
17083565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17093565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17103565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        @Override
17113565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void onInvalidated() {
17123565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            dismiss();
17133565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17143565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
17153565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17163565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private class ListSelectorHider implements Runnable {
17173565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void run() {
17183565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            clearListSelection();
17193565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17203565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
17213565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17223565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private class ResizePopupRunnable implements Runnable {
17233565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void run() {
17243565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
17253565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mDropDownList.getChildCount() <= mListItemExpandMaximum) {
17263565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
17273565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                show();
17283565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
17293565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17303565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
17313565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17323565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private class PopupTouchInterceptor implements OnTouchListener {
17333565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public boolean onTouch(View v, MotionEvent event) {
17343565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            final int action = event.getAction();
17353565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            final int x = (int) event.getX();
17363565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            final int y = (int) event.getY();
17373565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17383565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (action == MotionEvent.ACTION_DOWN &&
17393565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    mPopup != null && mPopup.isShowing() &&
17403565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    (x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
17413565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
17423565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            } else if (action == MotionEvent.ACTION_UP) {
17433565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mHandler.removeCallbacks(mResizePopupRunnable);
17443565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
17453565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            return false;
17463565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17473565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
17483565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17493565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    private class PopupScrollListener implements ListView.OnScrollListener {
17503565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
175120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns                int totalItemCount) {
17523565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17533565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17543565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani
17553565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        public void onScrollStateChanged(AbsListView view, int scrollState) {
17563565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
17573565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                    !isInputMethodNotNeeded() && mPopup.getContentView() != null) {
17583565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mHandler.removeCallbacks(mResizePopupRunnable);
17593565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani                mResizePopupRunnable.run();
17603565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani            }
17613565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani        }
17623565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani    }
176349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
176449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    private static boolean isConfirmKey(int keyCode) {
176549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes        return keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_CENTER;
176649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes    }
176749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes
1768ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes    private void setPopupClipToScreenEnabled(boolean clip) {
1769ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        if (sClipToWindowEnabledMethod != null) {
1770ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            try {
1771ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes                sClipToWindowEnabledMethod.invoke(mPopup, clip);
1772ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            } catch (Exception e) {
1773ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes                Log.i(TAG, "Could not call setClipToScreenEnabled() on PopupWindow. Oh well.");
1774ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes            }
1775ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes        }
1776ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes    }
1777ac00a989afc2f1c559fc33174f481a0a0ef5b3d8Chris Banes
17783565bf7048dfa3c5b5593d0df2259bd856f3b987Anirudh Dewani}