1c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell/* 2c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Copyright (C) 2010 The Android Open Source Project 3c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 4c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * you may not use this file except in compliance with the License. 6c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * You may obtain a copy of the License at 7c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 8c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 9c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 10c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Unless required by applicable law or agreed to in writing, software 11c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * See the License for the specific language governing permissions and 14c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * limitations under the License. 15c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 16c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 17c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellpackage android.widget; 18c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 19c05027214f1f4dda67296a072dfc9af9176dc590Alan Viveretteimport android.animation.Animator; 20c05027214f1f4dda67296a072dfc9af9176dc590Alan Viveretteimport android.animation.AnimatorListenerAdapter; 21c05027214f1f4dda67296a072dfc9af9176dc590Alan Viveretteimport android.animation.ObjectAnimator; 22c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.content.Context; 23f023c2530a4591889dda614aaa016d5a9f9617edAlan Viveretteimport android.content.res.TypedArray; 24c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.database.DataSetObserver; 25c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.graphics.Rect; 26c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.graphics.drawable.Drawable; 27c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.os.Handler; 2878efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viveretteimport android.os.SystemClock; 29d3d9f3f1004dfee2649a26cfe8dba948cd364904Fabrice Di Meglioimport android.text.TextUtils; 30c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.util.AttributeSet; 31c05027214f1f4dda67296a072dfc9af9176dc590Alan Viveretteimport android.util.IntProperty; 32c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.util.Log; 3354c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powellimport android.view.Gravity; 34c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.KeyEvent; 35c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.MotionEvent; 36c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.View; 37c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.View.MeasureSpec; 38c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellimport android.view.View.OnTouchListener; 39ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viveretteimport android.view.ViewConfiguration; 40711734a2f8d7529df0ed1bce36da651fc835c144Gilles Debunneimport android.view.ViewGroup; 41711734a2f8d7529df0ed1bce36da651fc835c144Gilles Debunneimport android.view.ViewParent; 42c05027214f1f4dda67296a072dfc9af9176dc590Alan Viveretteimport android.view.animation.AccelerateDecelerateInterpolator; 43c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 44f023c2530a4591889dda614aaa016d5a9f9617edAlan Viveretteimport com.android.internal.R; 455e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viveretteimport com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller; 465e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette 471d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglioimport java.util.Locale; 481d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio 49c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell/** 50c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * A ListPopupWindow anchors itself to a host view and displays a 5165d79fbe55c017edd9419ddb71939c8916471390Adam Powell * list of choices. 52c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 53c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>ListPopupWindow contains a number of tricky behaviors surrounding 54c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * positioning, scrolling parents to fit the dropdown, interacting 55c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * sanely with the IME if present, and others. 56c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 57c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see android.widget.AutoCompleteTextView 58c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see android.widget.Spinner 59c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 60c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powellpublic class ListPopupWindow { 61c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private static final String TAG = "ListPopupWindow"; 62c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private static final boolean DEBUG = false; 63c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 64c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 65c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * This value controls the length of time that the user 66c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * must leave a pointer down without scrolling to expand 67c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the autocomplete dropdown list to cover the IME. 68c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 69c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private static final int EXPAND_LIST_TIMEOUT = 250; 70c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 71c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private Context mContext; 72c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private PopupWindow mPopup; 73c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private ListAdapter mAdapter; 74c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private DropDownListView mDropDownList; 75c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 76c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT; 77c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT; 78c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int mDropDownHorizontalOffset; 79c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int mDropDownVerticalOffset; 808132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell private boolean mDropDownVerticalOffsetSet; 81c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 8254c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell private int mDropDownGravity = Gravity.NO_GRAVITY; 8354c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 84c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private boolean mDropDownAlwaysVisible = false; 85c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private boolean mForceIgnoreOutsideTouch = false; 86348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell int mListItemExpandMaximum = Integer.MAX_VALUE; 87c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 88c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private View mPromptView; 89c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int mPromptPosition = POSITION_PROMPT_ABOVE; 90c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 91c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private DataSetObserver mObserver; 92c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 93c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private View mDropDownAnchorView; 94c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 95c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private Drawable mDropDownListHighlight; 96c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 97c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private AdapterView.OnItemClickListener mItemClickListener; 98c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private AdapterView.OnItemSelectedListener mItemSelectedListener; 99c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1004267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable(); 101c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor(); 102c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private final PopupScrollListener mScrollListener = new PopupScrollListener(); 103c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private final ListSelectorHider mHideSelector = new ListSelectorHider(); 104c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private Runnable mShowDropDownRunnable; 105c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 106c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private Handler mHandler = new Handler(); 107c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 108c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private Rect mTempRect = new Rect(); 109c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 110c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private boolean mModal; 111c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1121d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio private int mLayoutDirection; 1131d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio 114c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 115c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * The provided prompt view should appear above list content. 116c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 117c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setPromptPosition(int) 118c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #getPromptPosition() 119c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setPromptView(View) 120c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 121c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int POSITION_PROMPT_ABOVE = 0; 122c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 123c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 124c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * The provided prompt view should appear below list content. 125c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 126c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setPromptPosition(int) 127c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #getPromptPosition() 128c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setPromptView(View) 129c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 130c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int POSITION_PROMPT_BELOW = 1; 131c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 132c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 133c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Alias for {@link ViewGroup.LayoutParams#MATCH_PARENT}. 134c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * If used to specify a popup width, the popup will match the width of the anchor view. 135c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * If used to specify a popup height, the popup will fill available space. 136c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 137c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; 138c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 139c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 140c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Alias for {@link ViewGroup.LayoutParams#WRAP_CONTENT}. 141c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * If used to specify a popup width, the popup will use the width of its content. 142c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 143c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; 144c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 145c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 146c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Mode for {@link #setInputMethodMode(int)}: the requirements for the 147c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * input method should be based on the focusability of the popup. That is 148c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * if it is focusable than it needs to work with the input method, else 149c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * it doesn't. 150c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 151c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int INPUT_METHOD_FROM_FOCUSABLE = PopupWindow.INPUT_METHOD_FROM_FOCUSABLE; 152c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 153c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 154c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Mode for {@link #setInputMethodMode(int)}: this popup always needs to 155c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * work with an input method, regardless of whether it is focusable. This 156c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * means that it will always be displayed so that the user can also operate 157c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the input method while it is shown. 158c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 159c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int INPUT_METHOD_NEEDED = PopupWindow.INPUT_METHOD_NEEDED; 160c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 161c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 162c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Mode for {@link #setInputMethodMode(int)}: this popup never needs to 163c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * work with an input method, regardless of whether it is focusable. This 164c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * means that it will always be displayed to use as much space on the 165c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * screen as needed, regardless of whether this covers the input method. 166c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 167c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public static final int INPUT_METHOD_NOT_NEEDED = PopupWindow.INPUT_METHOD_NOT_NEEDED; 168c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 169c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 170c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Create a new, empty popup window capable of displaying items from a ListAdapter. 171c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}. 172c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 173c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param context Context used for contained views. 174c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 175c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public ListPopupWindow(Context context) { 176c2238d006237ebf1296074d80fb4f4a2741ef880Daniel Lehmann this(context, null, com.android.internal.R.attr.listPopupWindowStyle, 0); 177c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 178c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 179c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 180c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Create a new, empty popup window capable of displaying items from a ListAdapter. 181c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}. 182c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 183c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param context Context used for contained views. 184c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param attrs Attributes from inflating parent views used to style the popup. 185c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 186c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public ListPopupWindow(Context context, AttributeSet attrs) { 1870b2d306e7000f4c0c6ad4e00d494bb401d8a9fc2Adam Powell this(context, attrs, com.android.internal.R.attr.listPopupWindowStyle, 0); 188c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 189c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 190c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 191c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Create a new, empty popup window capable of displaying items from a ListAdapter. 192c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}. 193c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 194c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param context Context used for contained views. 195c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param attrs Attributes from inflating parent views used to style the popup. 196c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param defStyleAttr Default style attribute to use for popup content. 197c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 198c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) { 199c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell this(context, attrs, defStyleAttr, 0); 200c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 201c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 202c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 203c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Create a new, empty popup window capable of displaying items from a ListAdapter. 204c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}. 205c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 206c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param context Context used for contained views. 207c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param attrs Attributes from inflating parent views used to style the popup. 208c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param defStyleAttr Style attribute to read for default styling of popup content. 209c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param defStyleRes Style resource ID to use for default styling of popup content. 210c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 211c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 212c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mContext = context; 213f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette 214f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow, 215f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette defStyleAttr, defStyleRes); 216f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette mDropDownHorizontalOffset = a.getDimensionPixelOffset( 217f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette R.styleable.ListPopupWindow_dropDownHorizontalOffset, 0); 218f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette mDropDownVerticalOffset = a.getDimensionPixelOffset( 219f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette R.styleable.ListPopupWindow_dropDownVerticalOffset, 0); 220f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette if (mDropDownVerticalOffset != 0) { 221f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette mDropDownVerticalOffsetSet = true; 222f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette } 223f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette a.recycle(); 224f023c2530a4591889dda614aaa016d5a9f9617edAlan Viverette 225c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes); 2266f5e934b96c400f610b1c5ad228cc60cab5d443fAdam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); 2271d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio // Set the default layout direction to match the default locale one 2281d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio final Locale locale = mContext.getResources().getConfiguration().locale; 229d3d9f3f1004dfee2649a26cfe8dba948cd364904Fabrice Di Meglio mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(locale); 230c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 231c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 232c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 233c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets the adapter that provides the data and the views to represent the data 234c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * in this popup window. 235c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 236c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param adapter The adapter to use to create this window's content. 237c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 238c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setAdapter(ListAdapter adapter) { 239c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mObserver == null) { 240c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mObserver = new PopupDataSetObserver(); 241c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (mAdapter != null) { 24299969da3772d9a0f5079672847ca4f2ad819c1bbAdam Powell mAdapter.unregisterDataSetObserver(mObserver); 243c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 244c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mAdapter = adapter; 245c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mAdapter != null) { 246c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell adapter.registerDataSetObserver(mObserver); 247c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 248c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 249c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownList != null) { 250c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setAdapter(mAdapter); 251c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 252c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 253c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 254c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 255c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set where the optional prompt view should appear. The default is 256c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * {@link #POSITION_PROMPT_ABOVE}. 257c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 258c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param position A position constant declaring where the prompt should be displayed. 259c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 260c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #POSITION_PROMPT_ABOVE 261c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #POSITION_PROMPT_BELOW 262c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 263c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setPromptPosition(int position) { 264c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPromptPosition = position; 265c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 266c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 267c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 268c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return Where the optional prompt view should appear. 269c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 270c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #POSITION_PROMPT_ABOVE 271c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #POSITION_PROMPT_BELOW 272c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 273c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getPromptPosition() { 274c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPromptPosition; 275c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 276c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 277c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 278c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set whether this window should be modal when shown. 279c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 280c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>If a popup window is modal, it will receive all touch and key input. 281c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * If the user touches outside the popup window's content area the popup window 282c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * will be dismissed. 283c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 284c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param modal {@code true} if the popup window should be modal, {@code false} otherwise. 285c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 286c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setModal(boolean modal) { 287e04499ad930ff4f112114683dc9f1e5411d6802bChet Haase mModal = modal; 288c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setFocusable(modal); 289c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 290c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 291c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 292c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Returns whether the popup window will be modal when shown. 293c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 294c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return {@code true} if the popup window will be modal, {@code false} otherwise. 295c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 296c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isModal() { 297c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mModal; 298c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 299c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 300c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 301c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is 302c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we 303c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * ignore outside touch even when the drop down is not set to always visible. 304c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 305c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @hide Used only by AutoCompleteTextView to handle some internal special cases. 306c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 307c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) { 308c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch; 309c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 310c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 311c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 312c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets whether the drop-down should remain visible under certain conditions. 313c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 314c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * The drop-down will occupy the entire screen below {@link #getAnchorView} regardless 315c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * of the size or content of the list. {@link #getBackground()} will fill any space 316c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * that is not used by the list. 317c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 318c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param dropDownAlwaysVisible Whether to keep the drop-down visible. 319c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 320c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @hide Only used by AutoCompleteTextView under special conditions. 321c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 322c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) { 323c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownAlwaysVisible = dropDownAlwaysVisible; 324c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 325c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 326c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 327c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return Whether the drop-down is visible under special conditions. 328c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 329c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @hide Only used by AutoCompleteTextView under special conditions. 330c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 331c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isDropDownAlwaysVisible() { 332c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownAlwaysVisible; 333c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 334c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 335c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 336c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets the operating mode for the soft input area. 337c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 338c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param mode The desired mode, see 339c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * {@link android.view.WindowManager.LayoutParams#softInputMode} 340c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * for the full list 341c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 342c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see android.view.WindowManager.LayoutParams#softInputMode 343c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #getSoftInputMode() 344c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 345c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setSoftInputMode(int mode) { 346c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setSoftInputMode(mode); 347c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 348c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 349c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 350c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Returns the current value in {@link #setSoftInputMode(int)}. 351c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 352c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setSoftInputMode(int) 353c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see android.view.WindowManager.LayoutParams#softInputMode 354c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 355c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getSoftInputMode() { 356c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.getSoftInputMode(); 357c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 358c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 359c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 360c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets a drawable to use as the list item selector. 361c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 362c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param selector List selector drawable to use in the popup. 363c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 364c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setListSelector(Drawable selector) { 365c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownListHighlight = selector; 366c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 367c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 368c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 369c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The background drawable for the popup window. 370c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 371c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public Drawable getBackground() { 372c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.getBackground(); 373c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 374c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 375c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 376c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets a drawable to be the background for the popup window. 377c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 378c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param d A drawable to set as the background. 379c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 380c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setBackgroundDrawable(Drawable d) { 381c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setBackgroundDrawable(d); 382c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 383c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 384c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 385c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set an animation style to use when the popup window is shown or dismissed. 386c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 387c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param animationStyle Animation style to use. 388c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 389c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setAnimationStyle(int animationStyle) { 390c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setAnimationStyle(animationStyle); 391c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 392c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 393c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 394c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Returns the animation style that will be used when the popup window is 395c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * shown or dismissed. 396c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 397c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return Animation style that will be used. 398c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 399c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getAnimationStyle() { 400c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.getAnimationStyle(); 401c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 402c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 403c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 404c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Returns the view that will be used to anchor this popup. 405c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 406c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The popup's anchor view 407c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 408c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public View getAnchorView() { 409c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownAnchorView; 410c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 411c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 412c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 413c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets the popup's anchor view. This popup will always be positioned relative to 414c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the anchor view when shown. 415c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 416c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param anchor The view to use as an anchor. 417c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 418c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setAnchorView(View anchor) { 419c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownAnchorView = anchor; 420c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 421c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 422c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 423c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The horizontal offset of the popup from its anchor in pixels. 424c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 425c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getHorizontalOffset() { 426c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownHorizontalOffset; 427c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 428c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 429c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 430c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set the horizontal offset of this popup from its anchor view in pixels. 431c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 432a984b38df5cfe6db0ba792bf2a6221f6b6072448Adam Powell * @param offset The horizontal offset of the popup from its anchor. 433c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 434c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setHorizontalOffset(int offset) { 435c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownHorizontalOffset = offset; 436c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 437c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 438c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 439c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The vertical offset of the popup from its anchor in pixels. 440c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 441c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getVerticalOffset() { 4428132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell if (!mDropDownVerticalOffsetSet) { 4438132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell return 0; 4448132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell } 445c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownVerticalOffset; 446c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 447c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 448c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 449c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set the vertical offset of this popup from its anchor view in pixels. 450c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 451a984b38df5cfe6db0ba792bf2a6221f6b6072448Adam Powell * @param offset The vertical offset of the popup from its anchor. 452c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 453c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setVerticalOffset(int offset) { 454c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownVerticalOffset = offset; 4558132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell mDropDownVerticalOffsetSet = true; 456c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 457c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 458c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 45954c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell * Set the gravity of the dropdown list. This is commonly used to 46054c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell * set gravity to START or END for alignment with the anchor. 46154c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell * 46254c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell * @param gravity Gravity value to use 46354c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell */ 46454c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell public void setDropDownGravity(int gravity) { 46554c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell mDropDownGravity = gravity; 46654c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell } 46754c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell 46854c94dea8a26e66fa59a31fd9170ca221052d3aaAdam Powell /** 469c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The width of the popup window in pixels. 470c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 471c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getWidth() { 472c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownWidth; 473c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 474c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 475c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 476c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets the width of the popup window in pixels. Can also be {@link #MATCH_PARENT} 477c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * or {@link #WRAP_CONTENT}. 478c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 479c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param width Width of the popup window. 480c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 481c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setWidth(int width) { 482c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownWidth = width; 483c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 484c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 485c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 4864267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * Sets the width of the popup window by the size of its content. The final width may be 4874267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * larger to accommodate styled window dressing. 4884267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * 4894267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell * @param width Desired width of content in pixels. 4904267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell */ 4914267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell public void setContentWidth(int width) { 4924267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell Drawable popupBackground = mPopup.getBackground(); 4934267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell if (popupBackground != null) { 494a39b987bb761899636ae1e3669d1343499d04ebdAdam Powell popupBackground.getPadding(mTempRect); 495a39b987bb761899636ae1e3669d1343499d04ebdAdam Powell mDropDownWidth = mTempRect.left + mTempRect.right + width; 49662e2bdecc21819a71c04204f20fc051886fdabd6Adam Powell } else { 49762e2bdecc21819a71c04204f20fc051886fdabd6Adam Powell setWidth(width); 4984267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 4994267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell } 5004267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell 5014267534d1c42af847ed0cefd1c88c99f66b36571Adam Powell /** 502c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The height of the popup window in pixels. 503c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 504c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getHeight() { 505c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownHeight; 506c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 507c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 508c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 509c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}. 510c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 511c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param height Height of the popup window. 512c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 513c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setHeight(int height) { 514c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownHeight = height; 515c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 516c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 517c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 518c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets a listener to receive events when a list item is clicked. 519c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 520c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param clickListener Listener to register 521c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 522c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener) 523c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 524c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) { 525c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mItemClickListener = clickListener; 526c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 527c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 528c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 529c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Sets a listener to receive events when a list item is selected. 530c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 531c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param selectedListener Listener to register. 532c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 533c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) 534c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 535c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) { 536c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mItemSelectedListener = selectedListener; 537c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 538c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 539c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 540c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set a view to act as a user prompt for this popup window. Where the prompt view will appear 541c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * is controlled by {@link #setPromptPosition(int)}. 542c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 543c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param prompt View to use as an informational prompt. 544c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 545c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setPromptView(View prompt) { 546c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell boolean showing = isShowing(); 547c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (showing) { 548c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell removePromptView(); 549c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 550c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPromptView = prompt; 551c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (showing) { 552c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell show(); 553c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 554c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 555c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 556c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 557c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Post a {@link #show()} call to the UI thread. 558c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 559c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void postShow() { 560c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHandler.post(mShowDropDownRunnable); 561c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 562c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 563c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 564c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Show the popup list. If the list is already showing, this method 565c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * will recalculate the popup's size and position. 566c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 567c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void show() { 568c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int height = buildDropDown(); 569c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 570c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int widthSpec = 0; 571c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int heightSpec = 0; 572c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 573c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell boolean noInputMethod = isInputMethodNotNeeded(); 574348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell mPopup.setAllowScrollingAnchorParent(!noInputMethod); 575c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 576c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mPopup.isShowing()) { 577c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) { 578c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // The call to PopupWindow's update method below can accept -1 for any 579c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // value you do not want to update. 580c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell widthSpec = -1; 581c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { 582c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell widthSpec = getAnchorView().getWidth(); 583c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 584c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell widthSpec = mDropDownWidth; 585c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 586c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 587c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { 588c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // The call to PopupWindow's update method below can accept -1 for any 589c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // value you do not want to update. 590c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT; 591c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (noInputMethod) { 592c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setWindowLayoutMode( 593c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 594c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ViewGroup.LayoutParams.MATCH_PARENT : 0, 0); 595c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 596c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setWindowLayoutMode( 597c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 598c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ViewGroup.LayoutParams.MATCH_PARENT : 0, 599c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ViewGroup.LayoutParams.MATCH_PARENT); 600c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 601c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { 602c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell heightSpec = height; 603c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 604c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell heightSpec = mDropDownHeight; 605c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 606c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 607c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible); 608c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 609c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.update(getAnchorView(), mDropDownHorizontalOffset, 610c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownVerticalOffset, widthSpec, heightSpec); 611c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 612c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) { 613c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell widthSpec = ViewGroup.LayoutParams.MATCH_PARENT; 614c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 615c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { 616c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setWidth(getAnchorView().getWidth()); 617c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 618c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setWidth(mDropDownWidth); 619c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 620c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 621c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 622c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { 623c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell heightSpec = ViewGroup.LayoutParams.MATCH_PARENT; 624c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 625c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { 626c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setHeight(height); 627c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 628c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setHeight(mDropDownHeight); 629c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 630c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 631c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 632c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setWindowLayoutMode(widthSpec, heightSpec); 63356c2d337e02a275397fc9d0460dca90977f199acAdam Powell mPopup.setClipToScreenEnabled(true); 634c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 635c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // use outside touchable to dismiss drop down when touching outside of it, so 636c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // only set this if the dropdown is not always visible 637c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible); 638c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setTouchInterceptor(mTouchInterceptor); 639560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset, 640560f17098f90b15c8894cce127f2fed85f7aeb6bAlan Viverette mDropDownVerticalOffset, mDropDownGravity); 641c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setSelection(ListView.INVALID_POSITION); 642c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 643c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!mModal || mDropDownList.isInTouchMode()) { 644c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell clearListSelection(); 645c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 646c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!mModal) { 647c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHandler.post(mHideSelector); 648c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 649c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 650c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 651c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 652c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 653c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Dismiss the popup window. 654c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 655c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void dismiss() { 656c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.dismiss(); 657c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell removePromptView(); 658c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setContentView(null); 659c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList = null; 660ca51e8788a58f2af3525b7214a675f2d0233e5daAdam Powell mHandler.removeCallbacks(mResizePopupRunnable); 661c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 662c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 6636c6f575423d6718c3ff322224c1520901ce881e1Adam Powell /** 6646c6f575423d6718c3ff322224c1520901ce881e1Adam Powell * Set a listener to receive a callback when the popup is dismissed. 6656c6f575423d6718c3ff322224c1520901ce881e1Adam Powell * 6666c6f575423d6718c3ff322224c1520901ce881e1Adam Powell * @param listener Listener that will be notified when the popup is dismissed. 6676c6f575423d6718c3ff322224c1520901ce881e1Adam Powell */ 6686c6f575423d6718c3ff322224c1520901ce881e1Adam Powell public void setOnDismissListener(PopupWindow.OnDismissListener listener) { 6696c6f575423d6718c3ff322224c1520901ce881e1Adam Powell mPopup.setOnDismissListener(listener); 6706c6f575423d6718c3ff322224c1520901ce881e1Adam Powell } 6716c6f575423d6718c3ff322224c1520901ce881e1Adam Powell 672c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private void removePromptView() { 673c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mPromptView != null) { 674c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final ViewParent parent = mPromptView.getParent(); 675c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (parent instanceof ViewGroup) { 676c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final ViewGroup group = (ViewGroup) parent; 677c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell group.removeView(mPromptView); 678c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 679c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 680c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 681c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 682c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 683c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Control how the popup operates with an input method: one of 684c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED}, 685c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * or {@link #INPUT_METHOD_NOT_NEEDED}. 686c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 687c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>If the popup is showing, calling this method will take effect only 688c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the next time the popup is shown or through a manual call to the {@link #show()} 689c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * method.</p> 690c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 691c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #getInputMethodMode() 692c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #show() 693c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 694c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setInputMethodMode(int mode) { 695c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setInputMethodMode(mode); 696c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 697c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 698c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 699c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Return the current value in {@link #setInputMethodMode(int)}. 700c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 701c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setInputMethodMode(int) 702c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 703c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getInputMethodMode() { 704c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.getInputMethodMode(); 705c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 706c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 707c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 708c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Set the selected position of the list. 709c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Only valid when {@link #isShowing()} == {@code true}. 710c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 711c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param position List position to set as selected. 712c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 713c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void setSelection(int position) { 714c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell DropDownListView list = mDropDownList; 715c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (isShowing() && list != null) { 716c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.mListSelectionHidden = false; 717c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.setSelection(position); 718c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) { 719c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.setItemChecked(position, true); 720c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 721c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 722c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 723c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 724c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 725c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Clear any current list selection. 726c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Only valid when {@link #isShowing()} == {@code true}. 727c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 728c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void clearListSelection() { 729c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final DropDownListView list = mDropDownList; 730c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (list != null) { 731c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // WARNING: Please read the comment where mListSelectionHidden is declared 732c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.mListSelectionHidden = true; 733c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.hideSelector(); 734c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell list.requestLayout(); 735c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 736c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 737c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 738c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 739c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return {@code true} if the popup is currently showing, {@code false} otherwise. 740c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 741c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isShowing() { 742c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.isShowing(); 743c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 744c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 745c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 746c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return {@code true} if this popup is configured to assume the user does not need 747c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * to interact with the IME while it is showing, {@code false} otherwise. 748c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 749c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isInputMethodNotNeeded() { 750c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mPopup.getInputMethodMode() == INPUT_METHOD_NOT_NEEDED; 751c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 752c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 753c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 754c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Perform an item click operation on the specified list adapter position. 755c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 756c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param position Adapter position for performing the click 757c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true if the click action could be performed, false if not. 758c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * (e.g. if the popup was not showing, this method would return false.) 759c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 760c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean performItemClick(int position) { 761c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (isShowing()) { 762c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mItemClickListener != null) { 763c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final DropDownListView list = mDropDownList; 764c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final View child = list.getChildAt(position - list.getFirstVisiblePosition()); 765cdee446075811e871fc2af295377bd99c100d16dAdam Powell final ListAdapter adapter = list.getAdapter(); 766cdee446075811e871fc2af295377bd99c100d16dAdam Powell mItemClickListener.onItemClick(list, child, position, adapter.getItemId(position)); 767c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 768c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 769c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 770c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return false; 771c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 772c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 773c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 774c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The currently selected item or null if the popup is not showing. 775c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 776c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public Object getSelectedItem() { 777c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!isShowing()) { 778c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return null; 779c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 780c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownList.getSelectedItem(); 781c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 782c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 783c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 784c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The position of the currently selected item or {@link ListView#INVALID_POSITION} 785c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * if {@link #isShowing()} == {@code false}. 786c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 787c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see ListView#getSelectedItemPosition() 788c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 789c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public int getSelectedItemPosition() { 790c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!isShowing()) { 791c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return ListView.INVALID_POSITION; 792c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 793c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownList.getSelectedItemPosition(); 794c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 795c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 796c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 797c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The ID of the currently selected item or {@link ListView#INVALID_ROW_ID} 798c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * if {@link #isShowing()} == {@code false}. 799c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 800c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see ListView#getSelectedItemId() 801c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 802c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public long getSelectedItemId() { 803c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!isShowing()) { 804c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return ListView.INVALID_ROW_ID; 805c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 806c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownList.getSelectedItemId(); 807c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 808c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 809c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 810c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The View for the currently selected item or null if 811c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * {@link #isShowing()} == {@code false}. 812c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 813c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see ListView#getSelectedView() 814c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 815c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public View getSelectedView() { 816c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (!isShowing()) { 817c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return null; 818c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 819c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownList.getSelectedView(); 820c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 821c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 822c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 823c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return The {@link ListView} displayed within the popup window. 824c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Only valid when {@link #isShowing()} == {@code true}. 825c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 826c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public ListView getListView() { 827c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mDropDownList; 828c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 829c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 830c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 831348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell * The maximum number of list items that can be visible and still have 832348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell * the list expand when touched. 833348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell * 834348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell * @param max Max number of items that can be visible and still allow the list to expand. 835348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell */ 836348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell void setListItemExpandMax(int max) { 837348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell mListItemExpandMaximum = max; 838348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell } 839348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell 840348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell /** 8418d6d3b83fb765eefc6fd38de77f1f45d2523ab89Jeff Brown * Filter key down events. By forwarding key down events to this function, 842c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * views using non-modal ListPopupWindow can have it handle key selection of items. 843c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 844c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param keyCode keyCode param passed to the host view's onKeyDown 845c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param event event param passed to the host view's onKeyDown 846c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true if the event was handled, false if it was ignored. 847c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 848c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setModal(boolean) 849c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 850c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean onKeyDown(int keyCode, KeyEvent event) { 851c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // when the drop down is shown, we drive it directly 852c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (isShowing()) { 853c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // the key events are forwarded to the list in the drop down view 854c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // note that ListView handles space but we don't want that to happen 855c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // also if selection is not currently in the drop down, then don't 856c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // let center or enter presses go there since that would cause it 857c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // to select one of its items 858c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (keyCode != KeyEvent.KEYCODE_SPACE 859c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell && (mDropDownList.getSelectedItemPosition() >= 0 86024d36f592224d1316165f579bb0937df0bf42f7cMichael Wright || !KeyEvent.isConfirmKey(keyCode))) { 861c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int curIndex = mDropDownList.getSelectedItemPosition(); 862c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell boolean consumed; 863c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 864c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final boolean below = !mPopup.isAboveAnchor(); 865c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 866c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final ListAdapter adapter = mAdapter; 867c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 868c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell boolean allEnabled; 869c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int firstItem = Integer.MAX_VALUE; 870c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int lastItem = Integer.MIN_VALUE; 871c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 872c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (adapter != null) { 873c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell allEnabled = adapter.areAllItemsEnabled(); 874c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell firstItem = allEnabled ? 0 : 875c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.lookForSelectablePosition(0, true); 876c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell lastItem = allEnabled ? adapter.getCount() - 1 : 877c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false); 878c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 879c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 880c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= firstItem) || 881c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell (!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >= lastItem)) { 882c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // When the selection is at the top, we block the key 883c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // event to prevent focus from moving. 884c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell clearListSelection(); 885c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); 886c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell show(); 887c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 888c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 889c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // WARNING: Please read the comment where mListSelectionHidden 890c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // is declared 891c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.mListSelectionHidden = false; 892c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 893c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 894c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell consumed = mDropDownList.onKeyDown(keyCode, event); 895c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + consumed); 896c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 897c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (consumed) { 898c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // If it handled the key event, then the user is 899c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // navigating in the list, so we should put it in front. 900c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 901c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // Here's a little trick we need to do to make sure that 902c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // the list view is actually showing its focus indicator, 903c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // by ensuring it has focus and getting its window out 904c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // of touch mode. 905c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.requestFocusFromTouch(); 906c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell show(); 907c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 908c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell switch (keyCode) { 909c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // avoid passing the focus from the text view to the 910c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // next component 911c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case KeyEvent.KEYCODE_ENTER: 912c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case KeyEvent.KEYCODE_DPAD_CENTER: 913c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case KeyEvent.KEYCODE_DPAD_DOWN: 914c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case KeyEvent.KEYCODE_DPAD_UP: 915c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 916c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 917c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 918c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 919c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // when the selection is at the bottom, we block the 920c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // event to avoid going to the next focusable widget 921c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (curIndex == lastItem) { 922c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 923c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 924c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (!below && keyCode == KeyEvent.KEYCODE_DPAD_UP && 925c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell curIndex == firstItem) { 926c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 927c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 928c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 929c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 930c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 931c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 932c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return false; 933c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 934c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 935c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 936c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Filter key down events. By forwarding key up events to this function, 937c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * views using non-modal ListPopupWindow can have it handle key selection of items. 938c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 939c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param keyCode keyCode param passed to the host view's onKeyUp 940c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param event event param passed to the host view's onKeyUp 941c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true if the event was handled, false if it was ignored. 942c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 943c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setModal(boolean) 944c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 945c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean onKeyUp(int keyCode, KeyEvent event) { 946c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) { 947c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell boolean consumed = mDropDownList.onKeyUp(keyCode, event); 94824d36f592224d1316165f579bb0937df0bf42f7cMichael Wright if (consumed && KeyEvent.isConfirmKey(keyCode)) { 94924d36f592224d1316165f579bb0937df0bf42f7cMichael Wright // if the list accepts the key events and the key event was a click, the text view 95024d36f592224d1316165f579bb0937df0bf42f7cMichael Wright // gets the selected item from the drop down as its content 95124d36f592224d1316165f579bb0937df0bf42f7cMichael Wright dismiss(); 952c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 953c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return consumed; 954c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 955c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return false; 956c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 957c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 958c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 959c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Filter pre-IME key events. By forwarding {@link View#onKeyPreIme(int, KeyEvent)} 960c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * events to this function, views using ListPopupWindow can have it dismiss the popup 961c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * when the back key is pressed. 962c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 963c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param keyCode keyCode param passed to the host view's onKeyPreIme 964c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param event event param passed to the host view's onKeyPreIme 965c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true if the event was handled, false if it was ignored. 966c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 967c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @see #setModal(boolean) 968c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 969c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean onKeyPreIme(int keyCode, KeyEvent event) { 970c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) { 971c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // special case for the back key, we do not even try to send it 972c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // to the drop down list but instead, consume it immediately 973c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final View anchorView = mDropDownAnchorView; 974c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { 975b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState(); 976b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown if (state != null) { 977b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown state.startTracking(event, this); 978b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown } 979c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 980c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (event.getAction() == KeyEvent.ACTION_UP) { 981b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState(); 982b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown if (state != null) { 983b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown state.handleUpEvent(event); 984b3ea92235c9ccc1ff295839a8f324dcd1c83dd6fJeff Brown } 985c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (event.isTracking() && !event.isCanceled()) { 986c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dismiss(); 987c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return true; 988c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 989c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 990c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 991c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return false; 992c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 993c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 994c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 9951955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * Returns an {@link OnTouchListener} that can be added to the source view 9961955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * to implement drag-to-open behavior. Generally, the source view should be 9971955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * the same view that was passed to {@link #setAnchorView}. 9981955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * <p> 9991955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * When the listener is set on a view, touching that view and dragging 10001955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * outside of its bounds will open the popup window. Lifting will select the 10011955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * currently touched list item. 10021955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * <p> 10031955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * Example usage: 10043f9832d3c7b30bf4dc8ed9e5123b02daca96c878Alan Viverette * <pre> 10053f9832d3c7b30bf4dc8ed9e5123b02daca96c878Alan Viverette * ListPopupWindow myPopup = new ListPopupWindow(context); 10061955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * myPopup.setAnchor(myAnchor); 10071955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * OnTouchListener dragListener = myPopup.createDragToOpenListener(myAnchor); 10083f9832d3c7b30bf4dc8ed9e5123b02daca96c878Alan Viverette * myAnchor.setOnTouchListener(dragListener); 10093f9832d3c7b30bf4dc8ed9e5123b02daca96c878Alan Viverette * </pre> 10101955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * 10111955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * @param src the view on which the resulting listener will be set 10121955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette * @return a touch listener that controls drag-to-open behavior 10131955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette */ 10141955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette public OnTouchListener createDragToOpenListener(View src) { 10151955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette return new ForwardingListener(src) { 10161955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette @Override 10171955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette public ListPopupWindow getPopup() { 10181955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette return ListPopupWindow.this; 10191955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette } 10201955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette }; 10211955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette } 10221955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette 10231955a5b531f03dec90f285b590ef62e3d632783cAlan Viverette /** 1024c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Builds the popup window's content and returns the height the popup 1025c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * should have. Returns -1 when the content already exists.</p> 1026c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1027c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return the content's height or -1 if content already exists 1028c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1029c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private int buildDropDown() { 1030c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ViewGroup dropDownView; 1031c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int otherHeights = 0; 1032c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1033c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownList == null) { 1034c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell Context context = mContext; 1035c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1036c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1037c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * This Runnable exists for the sole purpose of checking if the view layout has got 1038c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * completed and if so call showDropDown to display the drop down. This is used to show 1039c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the drop down as soon as possible after user opens up the search dialog, without 1040c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * waiting for the normal UI pipeline to do it's job which is slower than this method. 1041c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1042c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mShowDropDownRunnable = new Runnable() { 1043c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void run() { 1044c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // View layout should be all done before displaying the drop down. 1045c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell View view = getAnchorView(); 1046c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (view != null && view.getWindowToken() != null) { 1047c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell show(); 1048c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1049c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1050c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell }; 1051c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1052c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList = new DropDownListView(context, !mModal); 1053c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownListHighlight != null) { 1054c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setSelector(mDropDownListHighlight); 1055c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1056c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setAdapter(mAdapter); 1057c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setOnItemClickListener(mItemClickListener); 1058c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setFocusable(true); 1059c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setFocusableInTouchMode(true); 1060c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 1061c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onItemSelected(AdapterView<?> parent, View view, 1062c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int position, long id) { 1063c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1064c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (position != -1) { 1065c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell DropDownListView dropDownList = mDropDownList; 1066c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1067c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (dropDownList != null) { 1068c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dropDownList.mListSelectionHidden = false; 1069c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1070c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1071c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1072c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1073c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onNothingSelected(AdapterView<?> parent) { 1074c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1075c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell }); 1076c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setOnScrollListener(mScrollListener); 1077c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1078c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mItemSelectedListener != null) { 1079c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mDropDownList.setOnItemSelectedListener(mItemSelectedListener); 1080c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1081c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1082c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dropDownView = mDropDownList; 1083c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1084c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell View hintView = mPromptView; 1085c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (hintView != null) { 1086f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa // if a hint has been specified, we accomodate more space for it and 1087c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // add a text view in the drop down menu, at the bottom of the list 1088c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell LinearLayout hintContainer = new LinearLayout(context); 1089c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintContainer.setOrientation(LinearLayout.VERTICAL); 1090c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1091c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams( 1092c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f 1093c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ); 1094c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1095c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell switch (mPromptPosition) { 1096c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case POSITION_PROMPT_BELOW: 1097c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintContainer.addView(dropDownView, hintParams); 1098c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintContainer.addView(hintView); 1099c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell break; 1100c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1101c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell case POSITION_PROMPT_ABOVE: 1102c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintContainer.addView(hintView); 1103c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintContainer.addView(dropDownView, hintParams); 1104c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell break; 1105c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1106c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell default: 1107c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell Log.e(TAG, "Invalid hint position " + mPromptPosition); 1108c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell break; 1109c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1110c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1111c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // measure the hint's height to find how much more vertical space 1112c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // we need to add to the drop down's height 1113c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST); 1114c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int heightSpec = MeasureSpec.UNSPECIFIED; 1115c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintView.measure(widthSpec, heightSpec); 1116c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1117c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams(); 1118c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin 1119c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell + hintParams.bottomMargin; 1120c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1121c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dropDownView = hintContainer; 1122c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1123c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1124c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup.setContentView(dropDownView); 1125c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else { 1126c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dropDownView = (ViewGroup) mPopup.getContentView(); 1127c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final View view = mPromptView; 1128c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (view != null) { 1129c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell LinearLayout.LayoutParams hintParams = 1130c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell (LinearLayout.LayoutParams) view.getLayoutParams(); 1131c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell otherHeights = view.getMeasuredHeight() + hintParams.topMargin 1132c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell + hintParams.bottomMargin; 1133c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1134c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1135c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 11368132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell // getMaxAvailableHeight() subtracts the padding, so we put it back 1137c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // to get the available height for the whole window 1138c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int padding = 0; 1139c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell Drawable background = mPopup.getBackground(); 1140c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (background != null) { 1141c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell background.getPadding(mTempRect); 1142c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell padding = mTempRect.top + mTempRect.bottom; 11438132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell 11448132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell // If we don't have an explicit vertical offset, determine one from the window 11458132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell // background so that content will line up. 11468132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell if (!mDropDownVerticalOffsetSet) { 11478132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell mDropDownVerticalOffset = -mTempRect.top; 11488132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell } 11497507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell } else { 11507507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell mTempRect.setEmpty(); 1151c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1152c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 11538132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell // Max height available on the screen for a popup. 11548132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell boolean ignoreBottomDecorations = 11558132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; 11568132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell final int maxHeight = mPopup.getMaxAvailableHeight( 11578132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations); 11588132ba5e2e82d02697ef0570142abb8fc8054a67Adam Powell 1159c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { 1160c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return maxHeight + padding; 1161c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1162c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 11637507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell final int childWidthSpec; 11647507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell switch (mDropDownWidth) { 11657507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell case ViewGroup.LayoutParams.WRAP_CONTENT: 11667507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell childWidthSpec = MeasureSpec.makeMeasureSpec( 11677507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell mContext.getResources().getDisplayMetrics().widthPixels - 11687507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell (mTempRect.left + mTempRect.right), 11697507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell MeasureSpec.AT_MOST); 11707507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell break; 11717507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell case ViewGroup.LayoutParams.MATCH_PARENT: 11727507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell childWidthSpec = MeasureSpec.makeMeasureSpec( 11737507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell mContext.getResources().getDisplayMetrics().widthPixels - 11747507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell (mTempRect.left + mTempRect.right), 11757507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell MeasureSpec.EXACTLY); 11767507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell break; 11777507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell default: 11787507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell childWidthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.EXACTLY); 11797507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell break; 11807507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell } 11817507d3d31cb3d0ca190efc9d6b7ead5d6336f8d6Adam Powell final int listContent = mDropDownList.measureHeightOfChildren(childWidthSpec, 1182a7845ed44a3722e7d96ca9b677be213da7e8c8feAdam Powell 0, ListView.NO_POSITION, maxHeight - otherHeights, -1); 1183c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // add padding only if the list has items in it, that way we don't show 1184c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // the popup if it is not needed 1185c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (listContent > 0) otherHeights += padding; 1186c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1187c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return listContent + otherHeights; 1188c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1189c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 11901d3d7da331a3e9dc783819ab6fe29ea21c873f1eFabrice Di Meglio /** 1191ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Abstract class that forwards touch events to a {@link ListPopupWindow}. 1192ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1193ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @hide 1194ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 119569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette public static abstract class ForwardingListener 119669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette implements View.OnTouchListener, View.OnAttachStateChangeListener { 1197ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** Scaled touch slop, used for detecting movement outside bounds. */ 1198ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette private final float mScaledTouchSlop; 1199ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 120069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette /** Timeout before disallowing intercept on the source's parent. */ 120169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private final int mTapTimeout; 120269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 1203bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette /** Timeout before accepting a long-press to start forwarding. */ 1204bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private final int mLongPressTimeout; 1205bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 120669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette /** Source view from which events are forwarded. */ 120769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private final View mSrc; 120869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 120969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette /** Runnable used to prevent conflicts with scrolling parents. */ 121069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private Runnable mDisallowIntercept; 121169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 1212bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette /** Runnable used to trigger forwarding on long-press. */ 1213bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private Runnable mTriggerLongPress; 1214bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1215ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** Whether this listener is currently forwarding touch events. */ 1216ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette private boolean mForwarding; 1217ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1218bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette /** 1219bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette * Whether forwarding was initiated by a long-press. If so, we won't 1220bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette * force the window to dismiss when the touch stream ends. 1221bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette */ 1222bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private boolean mWasLongPress; 1223bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1224ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** The id of the first pointer down in the current event stream. */ 1225ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette private int mActivePointerId; 1226ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 122769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette public ForwardingListener(View src) { 122869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mSrc = src; 122969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop(); 123069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mTapTimeout = ViewConfiguration.getTapTimeout(); 123169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 1232bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette // Use a medium-press timeout. Halfway between tap and long-press. 1233bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2; 1234bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 123569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette src.addOnAttachStateChangeListener(this); 1236ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1237ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1238ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1239ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Returns the popup to which this listener is forwarding events. 1240ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * <p> 1241ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Override this to return the correct popup. If the popup is displayed 1242ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * asynchronously, you may also need to override 1243ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * {@link #onForwardingStopped} to prevent premature cancelation of 1244ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * forwarding. 1245ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1246ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @return the popup to which this listener is forwarding events 1247ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 1248ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette public abstract ListPopupWindow getPopup(); 1249ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1250ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette @Override 1251ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette public boolean onTouch(View v, MotionEvent event) { 1252ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final boolean wasForwarding = mForwarding; 1253ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final boolean forwarding; 1254ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (wasForwarding) { 125599b4e8507309f8e08ecc0baf994ccdc8020d6359Alan Viverette forwarding = onTouchForwarded(event) || !onForwardingStopped(); 1256ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } else { 125769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette forwarding = onTouchObserved(event) && onForwardingStarted(); 125878efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette 125978efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette if (forwarding) { 126078efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette // Make sure we cancel any ongoing source event stream. 126178efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette final long now = SystemClock.uptimeMillis(); 126278efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 126378efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette 0.0f, 0.0f, 0); 126478efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette mSrc.onTouchEvent(e); 126578efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette e.recycle(); 126678efdbac8a35a199f602e10a2d9ec3d86c0dbf5fAlan Viverette } 1267ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1268ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1269ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette mForwarding = forwarding; 1270ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return forwarding || wasForwarding; 1271ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1272ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 127369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette @Override 127469960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette public void onViewAttachedToWindow(View v) { 127569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 127669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 127769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette @Override 127869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette public void onViewDetachedFromWindow(View v) { 127969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mForwarding = false; 128069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mActivePointerId = MotionEvent.INVALID_POINTER_ID; 128169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 128269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette if (mDisallowIntercept != null) { 128369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mSrc.removeCallbacks(mDisallowIntercept); 128469960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 128569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 128669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 1287ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1288ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Called when forwarding would like to start. 1289ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * <p> 1290ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * By default, this will show the popup returned by {@link #getPopup()}. 1291ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * It may be overridden to perform another action, like clicking the 1292ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * source view or preparing the popup before showing it. 1293ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1294ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @return true to start forwarding, false otherwise 1295ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 129669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette protected boolean onForwardingStarted() { 1297ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final ListPopupWindow popup = getPopup(); 1298ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (popup != null && !popup.isShowing()) { 1299ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette popup.show(); 1300ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1301ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return true; 1302ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1303ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1304ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1305ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Called when forwarding would like to stop. 1306ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * <p> 1307ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * By default, this will dismiss the popup returned by 1308ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * {@link #getPopup()}. It may be overridden to perform some other 1309ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * action. 1310ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1311ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @return true to stop forwarding, false otherwise 1312ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 131369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette protected boolean onForwardingStopped() { 1314ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final ListPopupWindow popup = getPopup(); 1315ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (popup != null && popup.isShowing()) { 1316ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette popup.dismiss(); 1317ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1318ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return true; 1319ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1320ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1321ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1322ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Observes motion events and determines when to start forwarding. 1323ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1324ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @param srcEvent motion event in source view coordinates 1325ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @return true to start forwarding motion events, false otherwise 1326ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 132769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private boolean onTouchObserved(MotionEvent srcEvent) { 132869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final View src = mSrc; 1329ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (!src.isEnabled()) { 1330ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return false; 1331ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1332ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1333ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final int actionMasked = srcEvent.getActionMasked(); 133469960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette switch (actionMasked) { 133569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette case MotionEvent.ACTION_DOWN: 133669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mActivePointerId = srcEvent.getPointerId(0); 1337bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mWasLongPress = false; 1338bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 133969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette if (mDisallowIntercept == null) { 134069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette mDisallowIntercept = new DisallowIntercept(); 134169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 134269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette src.postDelayed(mDisallowIntercept, mTapTimeout); 1343bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1344bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette if (mTriggerLongPress == null) { 1345bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mTriggerLongPress = new TriggerLongPress(); 1346bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1347bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette src.postDelayed(mTriggerLongPress, mLongPressTimeout); 134869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette break; 134969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette case MotionEvent.ACTION_MOVE: 135069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId); 135169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette if (activePointerIndex >= 0) { 135269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final float x = srcEvent.getX(activePointerIndex); 135369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final float y = srcEvent.getY(activePointerIndex); 1354bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1355bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette // Has the pointer has moved outside of the view? 135669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette if (!src.pointInView(x, y, mScaledTouchSlop)) { 1357bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette clearCallbacks(); 1358bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1359bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette // Don't let the parent intercept our events. 136069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette src.getParent().requestDisallowInterceptTouchEvent(true); 136169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette return true; 136269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 136369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 136469960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette break; 136569960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette case MotionEvent.ACTION_CANCEL: 136669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette case MotionEvent.ACTION_UP: 1367bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette clearCallbacks(); 136869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette break; 1369ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1370ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1371ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return false; 1372ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1373ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1374bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private void clearCallbacks() { 1375bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette if (mTriggerLongPress != null) { 1376bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mSrc.removeCallbacks(mTriggerLongPress); 1377bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1378bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1379bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette if (mDisallowIntercept != null) { 1380bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mSrc.removeCallbacks(mDisallowIntercept); 1381bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1382bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1383bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1384bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private void onLongPress() { 1385bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette clearCallbacks(); 1386bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1387bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette final View src = mSrc; 1388298536b1a0873de211f8ab4588ec2acfb75f29f9Alan Viverette if (!src.isEnabled() || src.isLongClickable()) { 1389298536b1a0873de211f8ab4588ec2acfb75f29f9Alan Viverette // Ignore long-press if the view is disabled or has its own 1390298536b1a0873de211f8ab4588ec2acfb75f29f9Alan Viverette // handler. 1391bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette return; 1392bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1393bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1394bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette if (!onForwardingStarted()) { 1395bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette return; 1396bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1397bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1398bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette // Don't let the parent intercept our events. 1399298536b1a0873de211f8ab4588ec2acfb75f29f9Alan Viverette src.getParent().requestDisallowInterceptTouchEvent(true); 1400bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1401bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette // Make sure we cancel any ongoing source event stream. 1402bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette final long now = SystemClock.uptimeMillis(); 1403bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); 1404298536b1a0873de211f8ab4588ec2acfb75f29f9Alan Viverette src.onTouchEvent(e); 1405bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette e.recycle(); 1406bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1407bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mForwarding = true; 1408bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette mWasLongPress = true; 1409bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1410bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1411ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1412ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * Handled forwarded motion events and determines when to stop 1413ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * forwarding. 1414ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * 1415ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @param srcEvent motion event in source view coordinates 1416ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette * @return true to continue forwarding motion events, false to cancel 1417ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette */ 141869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private boolean onTouchForwarded(MotionEvent srcEvent) { 141969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final View src = mSrc; 1420ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final ListPopupWindow popup = getPopup(); 1421ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (popup == null || !popup.isShowing()) { 1422ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return false; 1423ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1424ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1425ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final DropDownListView dst = popup.mDropDownList; 1426ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette if (dst == null || !dst.isShown()) { 1427ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette return false; 1428ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1429ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1430ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette // Convert event to destination-local coordinates. 1431ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent); 1432ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette src.toGlobalMotionEvent(dstEvent); 1433ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette dst.toLocalMotionEvent(dstEvent); 1434ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1435ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette // Forward converted event to destination view, then recycle it. 1436ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId); 1437ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette dstEvent.recycle(); 1438d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette 1439d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette // Always cancel forwarding when the touch stream ends. 1440d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette final int action = srcEvent.getActionMasked(); 1441d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette final boolean keepForwarding = action != MotionEvent.ACTION_UP 1442d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette && action != MotionEvent.ACTION_CANCEL; 1443d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette 1444d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette return handled && keepForwarding; 1445ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 144669960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette 144769960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette private class DisallowIntercept implements Runnable { 144869960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette @Override 144969960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette public void run() { 145069960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette final ViewParent parent = mSrc.getParent(); 145169960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette parent.requestDisallowInterceptTouchEvent(true); 145269960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 145369960142efa8d228adbfcbabdcf618426e31e1f5Alan Viverette } 1454bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette 1455bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette private class TriggerLongPress implements Runnable { 1456bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette @Override 1457bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette public void run() { 1458bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette onLongPress(); 1459bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1460bca05f5ce7716b82f4b3d9221480a807aeb7ff15Alan Viverette } 1461ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette } 1462ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette 1463ca6a3611cdb28a514834adba35fcce2da6f2e7c2Alan Viverette /** 1464c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Wrapper class for a ListView. This wrapper can hijack the focus to 1465c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * make sure the list uses the appropriate drawables and states when 1466c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * displayed on screen within a drop down. The focus is never actually 1467c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * passed to the drop down in this mode; the list only looks focused.</p> 1468c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1469c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private static class DropDownListView extends ListView { 1470c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** Duration in milliseconds of the drag-to-open click animation. */ 1471c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private static final long CLICK_ANIM_DURATION = 150; 1472c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1473c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** Target alpha value for drag-to-open click animation. */ 1474c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private static final int CLICK_ANIM_ALPHA = 0x80; 1475c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1476c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** Wrapper around Drawable's <code>alpha</code> property. */ 1477c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private static final IntProperty<Drawable> DRAWABLE_ALPHA = 1478c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette new IntProperty<Drawable>("alpha") { 1479c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette @Override 1480c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette public void setValue(Drawable object, int value) { 1481c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette object.setAlpha(value); 1482c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1483c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1484c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette @Override 1485c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette public Integer get(Drawable object) { 1486c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette return object.getAlpha(); 1487c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1488c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette }; 1489c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1490c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /* 1491c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * WARNING: This is a workaround for a touch mode issue. 1492c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1493c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Touch mode is propagated lazily to windows. This causes problems in 1494c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the following scenario: 1495c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * - Type something in the AutoCompleteTextView and get some results 1496c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * - Move down with the d-pad to select an item in the list 1497c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * - Move up with the d-pad until the selection disappears 1498c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * - Type more text in the AutoCompleteTextView *using the soft keyboard* 1499c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * and get new results; you are now in touch mode 1500c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * - The selection comes back on the first item in the list, even though 1501c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * the list is supposed to be in touch mode 1502c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1503c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * Using the soft keyboard triggers the touch mode change but that change 1504c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * is propagated to our window only after the first list layout, therefore 1505c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * after the list attempts to resurrect the selection. 1506c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1507c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * The trick to work around this issue is to pretend the list is in touch 1508c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * mode when we know that the selection should not appear, that is when 1509c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * we know the user moved the selection away from the list. 1510c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1511c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * This boolean is set to true whenever we explicitly hide the list's 1512c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * selection and reset to false whenever we know the user moved the 1513c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * selection back to the list. 1514c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1515c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * When this boolean is true, isInTouchMode() returns true, otherwise it 1516c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * returns super.isInTouchMode(). 1517c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1518c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private boolean mListSelectionHidden; 1519c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1520c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1521c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * True if this wrapper should fake focus. 1522c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1523c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private boolean mHijackFocus; 1524c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1525c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** Whether to force drawing of the pressed state selector. */ 1526c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private boolean mDrawsInPressedState; 1527c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1528c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** Current drag-to-open click animation, if any. */ 1529c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private Animator mClickAnimation; 1530c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 15315e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette /** Helper for drag-to-open auto scrolling. */ 15325e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette private AbsListViewAutoScroller mScrollHelper; 15335e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette 1534c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1535c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Creates a new list view wrapper.</p> 1536c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1537c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param context this view's context 1538c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1539c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public DropDownListView(Context context, boolean hijackFocus) { 1540c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell super(context, null, com.android.internal.R.attr.dropDownListViewStyle); 1541c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHijackFocus = hijackFocus; 1542b1818e83f4a81bc4e4e30b99bb48830415be731bAmith Yamasani // TODO: Add an API to control this 1543b1818e83f4a81bc4e4e30b99bb48830415be731bAmith Yamasani setCacheColorHint(0); // Transparent, since the background drawable could be anything. 1544c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1545c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1546c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1547c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * Handles forwarded events. 1548c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * 1549c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * @param activePointerId id of the pointer that activated forwarding 1550c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * @return whether the event was handled 1551c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette */ 1552c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette public boolean onForwardedEvent(MotionEvent event, int activePointerId) { 1553c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette boolean handledEvent = true; 1554c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette boolean clearPressedItem = false; 1555c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1556c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final int actionMasked = event.getActionMasked(); 1557c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette switch (actionMasked) { 1558c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette case MotionEvent.ACTION_CANCEL: 1559c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette handledEvent = false; 1560c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette break; 1561c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette case MotionEvent.ACTION_UP: 1562c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette handledEvent = false; 1563c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette // $FALL-THROUGH$ 1564c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette case MotionEvent.ACTION_MOVE: 1565c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final int activeIndex = event.findPointerIndex(activePointerId); 1566c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (activeIndex < 0) { 1567c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette handledEvent = false; 1568c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette break; 1569c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1570c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1571c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final int x = (int) event.getX(activeIndex); 1572c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final int y = (int) event.getY(activeIndex); 1573c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final int position = pointToPosition(x, y); 1574c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (position == INVALID_POSITION) { 1575c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette clearPressedItem = true; 1576c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette break; 1577c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1578c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1579c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final View child = getChildAt(position - getFirstVisiblePosition()); 1580d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette setPressedItem(child, position, x, y); 1581c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette handledEvent = true; 1582c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1583c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (actionMasked == MotionEvent.ACTION_UP) { 1584c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette clickPressedItem(child, position); 1585c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1586c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette break; 1587c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1588c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1589c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette // Failure to handle the event cancels forwarding. 1590c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (!handledEvent || clearPressedItem) { 1591c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette clearPressedItem(); 1592c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1593c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 15945e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette // Manage automatic scrolling. 15955e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette if (handledEvent) { 15965e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette if (mScrollHelper == null) { 15975e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette mScrollHelper = new AbsListViewAutoScroller(this); 15985e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette } 15995e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette mScrollHelper.setEnabled(true); 16005e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette mScrollHelper.onTouch(this, event); 16015e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette } else if (mScrollHelper != null) { 16025e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette mScrollHelper.setEnabled(false); 16035e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette } 16045e66021c8a24c27c470cc6b9fe49e5653f3fa05dAlan Viverette 1605c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette return handledEvent; 1606c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1607c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1608c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** 1609c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * Starts an alpha animation on the selector. When the animation ends, 1610c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette * the list performs a click on the item. 1611c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette */ 1612c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private void clickPressedItem(final View child, final int position) { 1613c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final long id = getItemIdAtPosition(position); 1614c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette final Animator anim = ObjectAnimator.ofInt( 1615c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF); 1616c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette anim.setDuration(CLICK_ANIM_DURATION); 1617c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette anim.setInterpolator(new AccelerateDecelerateInterpolator()); 1618c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette anim.addListener(new AnimatorListenerAdapter() { 1619c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette @Override 1620c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette public void onAnimationEnd(Animator animation) { 1621c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette performItemClick(child, position, id); 1622c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1623c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette }); 1624c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette anim.start(); 1625c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1626c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (mClickAnimation != null) { 1627c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation.cancel(); 1628c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1629c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation = anim; 1630c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1631c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1632c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette private void clearPressedItem() { 1633c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mDrawsInPressedState = false; 1634c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette setPressed(false); 1635c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette updateSelectorState(); 1636c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 163762a8b61f929315c82448888a7addb0853f62293eAlan Viverette final View motionView = getChildAt(mMotionPosition - mFirstPosition); 163862a8b61f929315c82448888a7addb0853f62293eAlan Viverette if (motionView != null) { 163962a8b61f929315c82448888a7addb0853f62293eAlan Viverette motionView.setPressed(false); 164062a8b61f929315c82448888a7addb0853f62293eAlan Viverette } 164162a8b61f929315c82448888a7addb0853f62293eAlan Viverette 1642c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (mClickAnimation != null) { 1643c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation.cancel(); 1644c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation = null; 1645c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1646c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1647c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1648d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette private void setPressedItem(View child, int position, float x, float y) { 1649c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mDrawsInPressedState = true; 1650c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 16512563095d2d2798c05ebef81290c592826a1758f0Alan Viverette // Ordering is essential. First, update the container's pressed state. 16522563095d2d2798c05ebef81290c592826a1758f0Alan Viverette drawableHotspotChanged(x, y); 16532563095d2d2798c05ebef81290c592826a1758f0Alan Viverette if (!isPressed()) { 16542563095d2d2798c05ebef81290c592826a1758f0Alan Viverette setPressed(true); 16552563095d2d2798c05ebef81290c592826a1758f0Alan Viverette } 16562563095d2d2798c05ebef81290c592826a1758f0Alan Viverette 16572563095d2d2798c05ebef81290c592826a1758f0Alan Viverette // Next, run layout if we need to stabilize child positions. 16582563095d2d2798c05ebef81290c592826a1758f0Alan Viverette if (mDataChanged) { 16592563095d2d2798c05ebef81290c592826a1758f0Alan Viverette layoutChildren(); 16602563095d2d2798c05ebef81290c592826a1758f0Alan Viverette } 1661c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 166262a8b61f929315c82448888a7addb0853f62293eAlan Viverette // Manage the pressed view based on motion position. This allows us to 166362a8b61f929315c82448888a7addb0853f62293eAlan Viverette // play nicely with actual touch and scroll events. 166462a8b61f929315c82448888a7addb0853f62293eAlan Viverette final View motionView = getChildAt(mMotionPosition - mFirstPosition); 16652563095d2d2798c05ebef81290c592826a1758f0Alan Viverette if (motionView != null && motionView != child && motionView.isPressed()) { 166662a8b61f929315c82448888a7addb0853f62293eAlan Viverette motionView.setPressed(false); 166762a8b61f929315c82448888a7addb0853f62293eAlan Viverette } 166862a8b61f929315c82448888a7addb0853f62293eAlan Viverette mMotionPosition = position; 16692563095d2d2798c05ebef81290c592826a1758f0Alan Viverette 16702563095d2d2798c05ebef81290c592826a1758f0Alan Viverette // Offset for child coordinates. 16712563095d2d2798c05ebef81290c592826a1758f0Alan Viverette final float childX = x - child.getLeft(); 16722563095d2d2798c05ebef81290c592826a1758f0Alan Viverette final float childY = y - child.getTop(); 16732563095d2d2798c05ebef81290c592826a1758f0Alan Viverette child.drawableHotspotChanged(childX, childY); 16742563095d2d2798c05ebef81290c592826a1758f0Alan Viverette if (!child.isPressed()) { 16752563095d2d2798c05ebef81290c592826a1758f0Alan Viverette child.setPressed(true); 16762563095d2d2798c05ebef81290c592826a1758f0Alan Viverette } 167762a8b61f929315c82448888a7addb0853f62293eAlan Viverette 1678c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette // Ensure that keyboard focus starts from the last touched position. 1679c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette setSelectedPositionInt(position); 1680d361a4f98bbc03cb61b9ac4504eda490ff704b60Alan Viverette positionSelectorLikeTouch(position, child, x, y); 1681c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1682c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette // Refresh the drawable state to reflect the new pressed state, 1683c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette // which will also update the selector state. 1684c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette refreshDrawableState(); 1685c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1686c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette if (mClickAnimation != null) { 1687c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation.cancel(); 1688c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette mClickAnimation = null; 1689c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1690c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1691c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1692c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette @Override 1693c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette boolean touchModeDrawsInPressedState() { 1694c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette return mDrawsInPressedState || super.touchModeDrawsInPressedState(); 1695c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette } 1696c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette 1697c05027214f1f4dda67296a072dfc9af9176dc590Alan Viverette /** 1698c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Avoids jarring scrolling effect by ensuring that list elements 1699c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * made of a text view fit on a single line.</p> 1700c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1701c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @param position the item index in the list to get a view for 1702c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return the view for the specified item 1703c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1704c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1705c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell View obtainView(int position, boolean[] isScrap) { 1706c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell View view = super.obtainView(position, isScrap); 1707c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1708c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (view instanceof TextView) { 1709c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell ((TextView) view).setHorizontallyScrolling(true); 1710c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1711c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1712c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return view; 1713c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1714c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1715c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1716c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isInTouchMode() { 1717c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // WARNING: Please read the comment where mListSelectionHidden is declared 1718c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode(); 1719c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1720c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1721c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1722c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Returns the focus state in the drop down.</p> 1723c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1724c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true always if hijacking focus 1725c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1726c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1727c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean hasWindowFocus() { 1728c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mHijackFocus || super.hasWindowFocus(); 1729c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1730c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1731c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1732c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Returns the focus state in the drop down.</p> 1733c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1734c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true always if hijacking focus 1735c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1736c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1737c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean isFocused() { 1738c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mHijackFocus || super.isFocused(); 1739c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1740c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1741c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell /** 1742c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * <p>Returns the focus state in the drop down.</p> 1743c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * 1744c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell * @return true always if hijacking focus 1745c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell */ 1746c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1747c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean hasFocus() { 1748c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return mHijackFocus || super.hasFocus(); 1749c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1750c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1751c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1752c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private class PopupDataSetObserver extends DataSetObserver { 1753c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1754c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onChanged() { 1755c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (isShowing()) { 1756c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell // Resize the popup to fit new content 1757c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell show(); 1758c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1759c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1760c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1761c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell @Override 1762c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onInvalidated() { 1763c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell dismiss(); 1764c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1765c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1766c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1767c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private class ListSelectorHider implements Runnable { 1768c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void run() { 1769c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell clearListSelection(); 1770c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1771c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1772c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1773c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private class ResizePopupRunnable implements Runnable { 1774c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void run() { 1775348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() && 1776348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell mDropDownList.getChildCount() <= mListItemExpandMaximum) { 1777348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 1778348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell show(); 1779348e69cfabec21ccfbe708df06f0a7ea541a3053Adam Powell } 1780c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1781c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1782c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1783c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private class PopupTouchInterceptor implements OnTouchListener { 1784c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public boolean onTouch(View v, MotionEvent event) { 1785c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final int action = event.getAction(); 1786c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final int x = (int) event.getX(); 1787c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell final int y = (int) event.getY(); 1788c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1789c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (action == MotionEvent.ACTION_DOWN && 1790c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mPopup != null && mPopup.isShowing() && 1791711734a2f8d7529df0ed1bce36da651fc835c144Gilles Debunne (x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) { 1792c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT); 1793c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } else if (action == MotionEvent.ACTION_UP) { 1794c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHandler.removeCallbacks(mResizePopupRunnable); 1795c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1796c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell return false; 1797c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1798c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1799c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1800c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell private class PopupScrollListener implements ListView.OnScrollListener { 1801c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 1802c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell int totalItemCount) { 1803c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1804c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1805c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell 1806c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell public void onScrollStateChanged(AbsListView view, int scrollState) { 1807c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell if (scrollState == SCROLL_STATE_TOUCH_SCROLL && 1808c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell !isInputMethodNotNeeded() && mPopup.getContentView() != null) { 1809c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mHandler.removeCallbacks(mResizePopupRunnable); 1810c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell mResizePopupRunnable.run(); 1811c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1812c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1813c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell } 1814c3fa6304c997ccecf8ed15a4cbb7bd245128f3c3Adam Powell} 1815