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