Source code
package android.support.v7.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.text.TextUtilsCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.widget.ListViewAutoScrollHelper;
import android.support.v4.widget.PopupWindowCompat;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.AppCompatPopupWindow;
import android.support.v7.internal.widget.ListViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.KeyEvent.DispatcherState;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
import java.lang.reflect.Method;
public class ListPopupWindow {
private static final boolean DEBUG = false;
private static final int EXPAND_LIST_TIMEOUT = 250;
public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
public static final int INPUT_METHOD_NEEDED = 1;
public static final int INPUT_METHOD_NOT_NEEDED = 2;
public static final int MATCH_PARENT = -1;
public static final int POSITION_PROMPT_ABOVE = 0;
public static final int POSITION_PROMPT_BELOW = 1;
private static final String TAG = "ListPopupWindow";
public static final int WRAP_CONTENT = -2;
private static Method sClipToWindowEnabledMethod;
private static Method sGetMaxAvailableHeightMethod;
private ListAdapter mAdapter;
private Context mContext;
private boolean mDropDownAlwaysVisible;
private View mDropDownAnchorView;
private int mDropDownGravity;
private int mDropDownHeight;
private int mDropDownHorizontalOffset;
private DropDownListView mDropDownList;
private Drawable mDropDownListHighlight;
private int mDropDownVerticalOffset;
private boolean mDropDownVerticalOffsetSet;
private int mDropDownWidth;
private int mDropDownWindowLayoutType;
private boolean mForceIgnoreOutsideTouch;
private final Handler mHandler;
private final ListSelectorHider mHideSelector;
private OnItemClickListener mItemClickListener;
private OnItemSelectedListener mItemSelectedListener;
private int mLayoutDirection;
int mListItemExpandMaximum;
private boolean mModal;
private DataSetObserver mObserver;
private PopupWindow mPopup;
private int mPromptPosition;
private View mPromptView;
private final ResizePopupRunnable mResizePopupRunnable;
private final PopupScrollListener mScrollListener;
private Runnable mShowDropDownRunnable;
private Rect mTempRect;
private final PopupTouchInterceptor mTouchInterceptor;
public static abstract class ForwardingListener implements OnTouchListener {
private int mActivePointerId;
private Runnable mDisallowIntercept;
private boolean mForwarding;
private final int mLongPressTimeout;
private final float mScaledTouchSlop;
private final View mSrc;
private final int mTapTimeout;
private final int[] mTmpLocation = new int[2];
private Runnable mTriggerLongPress;
private boolean mWasLongPress;
private class DisallowIntercept implements Runnable {
private DisallowIntercept() {
}
public void run() {
ForwardingListener.this.mSrc.getParent().requestDisallowInterceptTouchEvent(true);
}
}
private class TriggerLongPress implements Runnable {
private TriggerLongPress() {
}
public void run() {
ForwardingListener.this.onLongPress();
}
}
public abstract ListPopupWindow getPopup();
public ForwardingListener(View src) {
this.mSrc = src;
this.mScaledTouchSlop = (float) ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
this.mTapTimeout = ViewConfiguration.getTapTimeout();
this.mLongPressTimeout = (this.mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
}
public boolean onTouch(View v, MotionEvent event) {
boolean forwarding;
boolean wasForwarding = this.mForwarding;
if (!wasForwarding) {
if (onTouchObserved(event) && onForwardingStarted()) {
forwarding = true;
} else {
forwarding = false;
}
if (forwarding) {
long now = SystemClock.uptimeMillis();
MotionEvent e = MotionEvent.obtain(now, now, 3, 0.0f, 0.0f, 0);
this.mSrc.onTouchEvent(e);
e.recycle();
}
} else if (this.mWasLongPress) {
forwarding = onTouchForwarded(event);
} else {
forwarding = onTouchForwarded(event) || !onForwardingStopped();
}
this.mForwarding = forwarding;
if (forwarding || wasForwarding) {
return true;
}
return false;
}
protected boolean onForwardingStarted() {
ListPopupWindow popup = getPopup();
if (!(popup == null || popup.isShowing())) {
popup.show();
}
return true;
}
protected boolean onForwardingStopped() {
ListPopupWindow popup = getPopup();
if (popup != null && popup.isShowing()) {
popup.dismiss();
}
return true;
}
private boolean onTouchObserved(MotionEvent srcEvent) {
View src = this.mSrc;
if (!src.isEnabled()) {
return false;
}
switch (MotionEventCompat.getActionMasked(srcEvent)) {
case 0:
this.mActivePointerId = srcEvent.getPointerId(0);
this.mWasLongPress = false;
if (this.mDisallowIntercept == null) {
this.mDisallowIntercept = new DisallowIntercept();
}
src.postDelayed(this.mDisallowIntercept, (long) this.mTapTimeout);
if (this.mTriggerLongPress == null) {
this.mTriggerLongPress = new TriggerLongPress();
}
src.postDelayed(this.mTriggerLongPress, (long) this.mLongPressTimeout);
return false;
case 1:
case 3:
clearCallbacks();
return false;
case 2:
int activePointerIndex = srcEvent.findPointerIndex(this.mActivePointerId);
if (activePointerIndex < 0 || pointInView(src, srcEvent.getX(activePointerIndex), srcEvent.getY(activePointerIndex), this.mScaledTouchSlop)) {
return false;
}
clearCallbacks();
src.getParent().requestDisallowInterceptTouchEvent(true);
return true;
default:
return false;
}
}
private void clearCallbacks() {
if (this.mTriggerLongPress != null) {
this.mSrc.removeCallbacks(this.mTriggerLongPress);
}
if (this.mDisallowIntercept != null) {
this.mSrc.removeCallbacks(this.mDisallowIntercept);
}
}
private void onLongPress() {
clearCallbacks();
View src = this.mSrc;
if (src.isEnabled() && !src.isLongClickable() && onForwardingStarted()) {
src.getParent().requestDisallowInterceptTouchEvent(true);
long now = SystemClock.uptimeMillis();
MotionEvent e = MotionEvent.obtain(now, now, 3, 0.0f, 0.0f, 0);
src.onTouchEvent(e);
e.recycle();
this.mForwarding = true;
this.mWasLongPress = true;
}
}
private boolean onTouchForwarded(MotionEvent srcEvent) {
boolean z = true;
View src = this.mSrc;
ListPopupWindow popup = getPopup();
if (popup == null || !popup.isShowing()) {
return false;
}
DropDownListView dst = popup.mDropDownList;
if (dst == null || !dst.isShown()) {
return false;
}
MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
toGlobalMotionEvent(src, dstEvent);
toLocalMotionEvent(dst, dstEvent);
boolean handled = dst.onForwardedEvent(dstEvent, this.mActivePointerId);
dstEvent.recycle();
int action = MotionEventCompat.getActionMasked(srcEvent);
boolean keepForwarding;
if (action == 1 || action == 3) {
keepForwarding = false;
} else {
keepForwarding = true;
}
if (!(handled && keepForwarding)) {
z = false;
}
return z;
}
private static boolean pointInView(View view, float localX, float localY, float slop) {
return localX >= (-slop) && localY >= (-slop) && localX < ((float) (view.getRight() - view.getLeft())) + slop && localY < ((float) (view.getBottom() - view.getTop())) + slop;
}
private boolean toLocalMotionEvent(View view, MotionEvent event) {
int[] loc = this.mTmpLocation;
view.getLocationOnScreen(loc);
event.offsetLocation((float) (-loc[0]), (float) (-loc[1]));
return true;
}
private boolean toGlobalMotionEvent(View view, MotionEvent event) {
int[] loc = this.mTmpLocation;
view.getLocationOnScreen(loc);
event.offsetLocation((float) loc[0], (float) loc[1]);
return true;
}
}
private class ListSelectorHider implements Runnable {
private ListSelectorHider() {
}
public void run() {
ListPopupWindow.this.clearListSelection();
}
}
private class PopupDataSetObserver extends DataSetObserver {
private PopupDataSetObserver() {
}
public void onChanged() {
if (ListPopupWindow.this.isShowing()) {
ListPopupWindow.this.show();
}
}
public void onInvalidated() {
ListPopupWindow.this.dismiss();
}
}
private class PopupScrollListener implements OnScrollListener {
private PopupScrollListener() {
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == 1 && !ListPopupWindow.this.isInputMethodNotNeeded() && ListPopupWindow.this.mPopup.getContentView() != null) {
ListPopupWindow.this.mHandler.removeCallbacks(ListPopupWindow.this.mResizePopupRunnable);
ListPopupWindow.this.mResizePopupRunnable.run();
}
}
}
private class PopupTouchInterceptor implements OnTouchListener {
private PopupTouchInterceptor() {
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
if (action == 0 && ListPopupWindow.this.mPopup != null && ListPopupWindow.this.mPopup.isShowing() && x >= 0 && x < ListPopupWindow.this.mPopup.getWidth() && y >= 0 && y < ListPopupWindow.this.mPopup.getHeight()) {
ListPopupWindow.this.mHandler.postDelayed(ListPopupWindow.this.mResizePopupRunnable, 250);
} else if (action == 1) {
ListPopupWindow.this.mHandler.removeCallbacks(ListPopupWindow.this.mResizePopupRunnable);
}
return false;
}
}
private class ResizePopupRunnable implements Runnable {
private ResizePopupRunnable() {
}
public void run() {
if (ListPopupWindow.this.mDropDownList != null && ViewCompat.isAttachedToWindow(ListPopupWindow.this.mDropDownList) && ListPopupWindow.this.mDropDownList.getCount() > ListPopupWindow.this.mDropDownList.getChildCount() && ListPopupWindow.this.mDropDownList.getChildCount() <= ListPopupWindow.this.mListItemExpandMaximum) {
ListPopupWindow.this.mPopup.setInputMethodMode(2);
ListPopupWindow.this.show();
}
}
}
private static class DropDownListView extends ListViewCompat {
private ViewPropertyAnimatorCompat mClickAnimation;
private boolean mDrawsInPressedState;
private boolean mHijackFocus;
private boolean mListSelectionHidden;
private ListViewAutoScrollHelper mScrollHelper;
public DropDownListView(Context context, boolean hijackFocus) {
super(context, null, R.attr.dropDownListViewStyle);
this.mHijackFocus = hijackFocus;
setCacheColorHint(0);
}
public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
boolean handledEvent = true;
boolean clearPressedItem = false;
int actionMasked = MotionEventCompat.getActionMasked(event);
switch (actionMasked) {
case 1:
handledEvent = false;
break;
case 2:
break;
case 3:
handledEvent = false;
break;
}
int activeIndex = event.findPointerIndex(activePointerId);
if (activeIndex < 0) {
handledEvent = false;
} else {
int x = (int) event.getX(activeIndex);
int y = (int) event.getY(activeIndex);
int position = pointToPosition(x, y);
if (position == -1) {
clearPressedItem = true;
} else {
View child = getChildAt(position - getFirstVisiblePosition());
setPressedItem(child, position, (float) x, (float) y);
handledEvent = true;
if (actionMasked == 1) {
clickPressedItem(child, position);
}
}
}
if (!handledEvent || clearPressedItem) {
clearPressedItem();
}
if (handledEvent) {
if (this.mScrollHelper == null) {
this.mScrollHelper = new ListViewAutoScrollHelper(this);
}
this.mScrollHelper.setEnabled(true);
this.mScrollHelper.onTouch(this, event);
} else if (this.mScrollHelper != null) {
this.mScrollHelper.setEnabled(false);
}
return handledEvent;
}
private void clickPressedItem(View child, int position) {
performItemClick(child, position, getItemIdAtPosition(position));
}
private void clearPressedItem() {
this.mDrawsInPressedState = false;
setPressed(false);
drawableStateChanged();
View motionView = getChildAt(this.mMotionPosition - getFirstVisiblePosition());
if (motionView != null) {
motionView.setPressed(false);
}
if (this.mClickAnimation != null) {
this.mClickAnimation.cancel();
this.mClickAnimation = null;
}
}
private void setPressedItem(View child, int position, float x, float y) {
this.mDrawsInPressedState = true;
if (VERSION.SDK_INT >= 21) {
drawableHotspotChanged(x, y);
}
if (!isPressed()) {
setPressed(true);
}
layoutChildren();
if (this.mMotionPosition != -1) {
View motionView = getChildAt(this.mMotionPosition - getFirstVisiblePosition());
if (!(motionView == null || motionView == child || !motionView.isPressed())) {
motionView.setPressed(false);
}
}
this.mMotionPosition = position;
float childX = x - ((float) child.getLeft());
float childY = y - ((float) child.getTop());
if (VERSION.SDK_INT >= 21) {
child.drawableHotspotChanged(childX, childY);
}
if (!child.isPressed()) {
child.setPressed(true);
}
setSelection(position);
positionSelectorLikeTouchCompat(position, child, x, y);
setSelectorEnabled(false);
refreshDrawableState();
}
protected boolean touchModeDrawsInPressedStateCompat() {
return this.mDrawsInPressedState || super.touchModeDrawsInPressedStateCompat();
}
public boolean isInTouchMode() {
return (this.mHijackFocus && this.mListSelectionHidden) || super.isInTouchMode();
}
public boolean hasWindowFocus() {
return this.mHijackFocus || super.hasWindowFocus();
}
public boolean isFocused() {
return this.mHijackFocus || super.isFocused();
}
public boolean hasFocus() {
return this.mHijackFocus || super.hasFocus();
}
}
static {
try {
sClipToWindowEnabledMethod = PopupWindow.class.getDeclaredMethod("setClipToScreenEnabled", new Class[]{Boolean.TYPE});
} catch (NoSuchMethodException e) {
Log.i(TAG, "Could not find method setClipToScreenEnabled() on PopupWindow. Oh well.");
}
try {
sGetMaxAvailableHeightMethod = PopupWindow.class.getDeclaredMethod("getMaxAvailableHeight", new Class[]{View.class, Integer.TYPE, Boolean.TYPE});
} catch (NoSuchMethodException e2) {
Log.i(TAG, "Could not find method getMaxAvailableHeight(View, int, boolean) on PopupWindow. Oh well.");
}
}
public ListPopupWindow(Context context) {
this(context, null, R.attr.listPopupWindowStyle);
}
public ListPopupWindow(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.listPopupWindowStyle);
}
public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this.mDropDownHeight = -2;
this.mDropDownWidth = -2;
this.mDropDownWindowLayoutType = 1002;
this.mDropDownGravity = 0;
this.mDropDownAlwaysVisible = false;
this.mForceIgnoreOutsideTouch = false;
this.mListItemExpandMaximum = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED;
this.mPromptPosition = 0;
this.mResizePopupRunnable = new ResizePopupRunnable();
this.mTouchInterceptor = new PopupTouchInterceptor();
this.mScrollListener = new PopupScrollListener();
this.mHideSelector = new ListSelectorHider();
this.mTempRect = new Rect();
this.mContext = context;
this.mHandler = new Handler(context.getMainLooper());
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow, defStyleAttr, defStyleRes);
this.mDropDownHorizontalOffset = a.getDimensionPixelOffset(R.styleable.ListPopupWindow_android_dropDownHorizontalOffset, 0);
this.mDropDownVerticalOffset = a.getDimensionPixelOffset(R.styleable.ListPopupWindow_android_dropDownVerticalOffset, 0);
if (this.mDropDownVerticalOffset != 0) {
this.mDropDownVerticalOffsetSet = true;
}
a.recycle();
this.mPopup = new AppCompatPopupWindow(context, attrs, defStyleAttr);
this.mPopup.setInputMethodMode(1);
this.mLayoutDirection = TextUtilsCompat.getLayoutDirectionFromLocale(this.mContext.getResources().getConfiguration().locale);
}
public void setAdapter(ListAdapter adapter) {
if (this.mObserver == null) {
this.mObserver = new PopupDataSetObserver();
} else if (this.mAdapter != null) {
this.mAdapter.unregisterDataSetObserver(this.mObserver);
}
this.mAdapter = adapter;
if (this.mAdapter != null) {
adapter.registerDataSetObserver(this.mObserver);
}
if (this.mDropDownList != null) {
this.mDropDownList.setAdapter(this.mAdapter);
}
}
public void setPromptPosition(int position) {
this.mPromptPosition = position;
}
public int getPromptPosition() {
return this.mPromptPosition;
}
public void setModal(boolean modal) {
this.mModal = modal;
this.mPopup.setFocusable(modal);
}
public boolean isModal() {
return this.mModal;
}
public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
this.mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch;
}
public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
this.mDropDownAlwaysVisible = dropDownAlwaysVisible;
}
public boolean isDropDownAlwaysVisible() {
return this.mDropDownAlwaysVisible;
}
public void setSoftInputMode(int mode) {
this.mPopup.setSoftInputMode(mode);
}
public int getSoftInputMode() {
return this.mPopup.getSoftInputMode();
}
public void setListSelector(Drawable selector) {
this.mDropDownListHighlight = selector;
}
public Drawable getBackground() {
return this.mPopup.getBackground();
}
public void setBackgroundDrawable(Drawable d) {
this.mPopup.setBackgroundDrawable(d);
}
public void setAnimationStyle(int animationStyle) {
this.mPopup.setAnimationStyle(animationStyle);
}
public int getAnimationStyle() {
return this.mPopup.getAnimationStyle();
}
public View getAnchorView() {
return this.mDropDownAnchorView;
}
public void setAnchorView(View anchor) {
this.mDropDownAnchorView = anchor;
}
public int getHorizontalOffset() {
return this.mDropDownHorizontalOffset;
}
public void setHorizontalOffset(int offset) {
this.mDropDownHorizontalOffset = offset;
}
public int getVerticalOffset() {
if (this.mDropDownVerticalOffsetSet) {
return this.mDropDownVerticalOffset;
}
return 0;
}
public void setVerticalOffset(int offset) {
this.mDropDownVerticalOffset = offset;
this.mDropDownVerticalOffsetSet = true;
}
public void setDropDownGravity(int gravity) {
this.mDropDownGravity = gravity;
}
public int getWidth() {
return this.mDropDownWidth;
}
public void setWidth(int width) {
this.mDropDownWidth = width;
}
public void setContentWidth(int width) {
Drawable popupBackground = this.mPopup.getBackground();
if (popupBackground != null) {
popupBackground.getPadding(this.mTempRect);
this.mDropDownWidth = (this.mTempRect.left + this.mTempRect.right) + width;
return;
}
setWidth(width);
}
public int getHeight() {
return this.mDropDownHeight;
}
public void setHeight(int height) {
this.mDropDownHeight = height;
}
public void setWindowLayoutType(int layoutType) {
this.mDropDownWindowLayoutType = layoutType;
}
public void setOnItemClickListener(OnItemClickListener clickListener) {
this.mItemClickListener = clickListener;
}
public void setOnItemSelectedListener(OnItemSelectedListener selectedListener) {
this.mItemSelectedListener = selectedListener;
}
public void setPromptView(View prompt) {
boolean showing = isShowing();
if (showing) {
removePromptView();
}
this.mPromptView = prompt;
if (showing) {
show();
}
}
public void postShow() {
this.mHandler.post(this.mShowDropDownRunnable);
}
public void show() {
boolean z = true;
boolean z2 = false;
int i = -1;
int height = buildDropDown();
boolean noInputMethod = isInputMethodNotNeeded();
PopupWindowCompat.setWindowLayoutType(this.mPopup, this.mDropDownWindowLayoutType);
int widthSpec;
int heightSpec;
if (this.mPopup.isShowing()) {
int i2;
if (this.mDropDownWidth == -1) {
widthSpec = -1;
} else if (this.mDropDownWidth == -2) {
widthSpec = getAnchorView().getWidth();
} else {
widthSpec = this.mDropDownWidth;
}
if (this.mDropDownHeight == -1) {
if (noInputMethod) {
heightSpec = height;
} else {
heightSpec = -1;
}
PopupWindow popupWindow;
int i3;
if (noInputMethod) {
popupWindow = this.mPopup;
if (this.mDropDownWidth == -1) {
i3 = -1;
} else {
i3 = 0;
}
popupWindow.setWidth(i3);
this.mPopup.setHeight(0);
} else {
popupWindow = this.mPopup;
if (this.mDropDownWidth == -1) {
i3 = -1;
} else {
i3 = 0;
}
popupWindow.setWidth(i3);
this.mPopup.setHeight(-1);
}
} else if (this.mDropDownHeight == -2) {
heightSpec = height;
} else {
heightSpec = this.mDropDownHeight;
}
PopupWindow popupWindow2 = this.mPopup;
if (!(this.mForceIgnoreOutsideTouch || this.mDropDownAlwaysVisible)) {
z2 = true;
}
popupWindow2.setOutsideTouchable(z2);
popupWindow2 = this.mPopup;
View anchorView = getAnchorView();
int i4 = this.mDropDownHorizontalOffset;
int i5 = this.mDropDownVerticalOffset;
if (widthSpec < 0) {
i2 = -1;
} else {
i2 = widthSpec;
}
if (heightSpec >= 0) {
i = heightSpec;
}
popupWindow2.update(anchorView, i4, i5, i2, i);
return;
}
if (this.mDropDownWidth == -1) {
widthSpec = -1;
} else if (this.mDropDownWidth == -2) {
widthSpec = getAnchorView().getWidth();
} else {
widthSpec = this.mDropDownWidth;
}
if (this.mDropDownHeight == -1) {
heightSpec = -1;
} else if (this.mDropDownHeight == -2) {
heightSpec = height;
} else {
heightSpec = this.mDropDownHeight;
}
this.mPopup.setWidth(widthSpec);
this.mPopup.setHeight(heightSpec);
setPopupClipToScreenEnabled(true);
popupWindow2 = this.mPopup;
if (this.mForceIgnoreOutsideTouch || this.mDropDownAlwaysVisible) {
z = false;
}
popupWindow2.setOutsideTouchable(z);
this.mPopup.setTouchInterceptor(this.mTouchInterceptor);
PopupWindowCompat.showAsDropDown(this.mPopup, getAnchorView(), this.mDropDownHorizontalOffset, this.mDropDownVerticalOffset, this.mDropDownGravity);
this.mDropDownList.setSelection(-1);
if (!this.mModal || this.mDropDownList.isInTouchMode()) {
clearListSelection();
}
if (!this.mModal) {
this.mHandler.post(this.mHideSelector);
}
}
public void dismiss() {
this.mPopup.dismiss();
removePromptView();
this.mPopup.setContentView(null);
this.mDropDownList = null;
this.mHandler.removeCallbacks(this.mResizePopupRunnable);
}
public void setOnDismissListener(OnDismissListener listener) {
this.mPopup.setOnDismissListener(listener);
}
private void removePromptView() {
if (this.mPromptView != null) {
ViewParent parent = this.mPromptView.getParent();
if (parent instanceof ViewGroup) {
((ViewGroup) parent).removeView(this.mPromptView);
}
}
}
public void setInputMethodMode(int mode) {
this.mPopup.setInputMethodMode(mode);
}
public int getInputMethodMode() {
return this.mPopup.getInputMethodMode();
}
public void setSelection(int position) {
DropDownListView list = this.mDropDownList;
if (isShowing() && list != null) {
list.mListSelectionHidden = false;
list.setSelection(position);
if (VERSION.SDK_INT >= 11 && list.getChoiceMode() != 0) {
list.setItemChecked(position, true);
}
}
}
public void clearListSelection() {
DropDownListView list = this.mDropDownList;
if (list != null) {
list.mListSelectionHidden = true;
list.requestLayout();
}
}
public boolean isShowing() {
return this.mPopup.isShowing();
}
public boolean isInputMethodNotNeeded() {
return this.mPopup.getInputMethodMode() == 2;
}
public boolean performItemClick(int position) {
if (!isShowing()) {
return false;
}
if (this.mItemClickListener != null) {
DropDownListView list = this.mDropDownList;
int i = position;
this.mItemClickListener.onItemClick(list, list.getChildAt(position - list.getFirstVisiblePosition()), i, list.getAdapter().getItemId(position));
}
return true;
}
public Object getSelectedItem() {
if (isShowing()) {
return this.mDropDownList.getSelectedItem();
}
return null;
}
public int getSelectedItemPosition() {
if (isShowing()) {
return this.mDropDownList.getSelectedItemPosition();
}
return -1;
}
public long getSelectedItemId() {
if (isShowing()) {
return this.mDropDownList.getSelectedItemId();
}
return Long.MIN_VALUE;
}
public View getSelectedView() {
if (isShowing()) {
return this.mDropDownList.getSelectedView();
}
return null;
}
public ListView getListView() {
return this.mDropDownList;
}
void setListItemExpandMax(int max) {
this.mListItemExpandMaximum = max;
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (isShowing() && keyCode != 62 && (this.mDropDownList.getSelectedItemPosition() >= 0 || !isConfirmKey(keyCode))) {
boolean below;
int curIndex = this.mDropDownList.getSelectedItemPosition();
if (this.mPopup.isAboveAnchor()) {
below = false;
} else {
below = true;
}
ListAdapter adapter = this.mAdapter;
int firstItem = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED;
int lastItem = Integer.MIN_VALUE;
if (adapter != null) {
boolean allEnabled = adapter.areAllItemsEnabled();
firstItem = allEnabled ? 0 : this.mDropDownList.lookForSelectablePosition(0, true);
if (allEnabled) {
lastItem = adapter.getCount() - 1;
} else {
lastItem = this.mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
}
}
if (!(below && keyCode == 19 && curIndex <= firstItem) && (below || keyCode != 20 || curIndex < lastItem)) {
this.mDropDownList.mListSelectionHidden = false;
if (this.mDropDownList.onKeyDown(keyCode, event)) {
this.mPopup.setInputMethodMode(2);
this.mDropDownList.requestFocusFromTouch();
show();
switch (keyCode) {
case 19:
case 20:
case 23:
case 66:
return true;
}
} else if (below && keyCode == 20) {
if (curIndex == lastItem) {
return true;
}
} else if (!below && keyCode == 19 && curIndex == firstItem) {
return true;
}
}
clearListSelection();
this.mPopup.setInputMethodMode(1);
show();
return true;
}
return false;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (!isShowing() || this.mDropDownList.getSelectedItemPosition() < 0) {
return false;
}
boolean consumed = this.mDropDownList.onKeyUp(keyCode, event);
if (!consumed || !isConfirmKey(keyCode)) {
return consumed;
}
dismiss();
return consumed;
}
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == 4 && isShowing()) {
View anchorView = this.mDropDownAnchorView;
DispatcherState state;
if (event.getAction() == 0 && event.getRepeatCount() == 0) {
state = anchorView.getKeyDispatcherState();
if (state == null) {
return true;
}
state.startTracking(event, this);
return true;
} else if (event.getAction() == 1) {
state = anchorView.getKeyDispatcherState();
if (state != null) {
state.handleUpEvent(event);
}
if (event.isTracking() && !event.isCanceled()) {
dismiss();
return true;
}
}
}
return false;
}
public OnTouchListener createDragToOpenListener(View src) {
return new ForwardingListener(src) {
public ListPopupWindow getPopup() {
return ListPopupWindow.this;
}
};
}
private int buildDropDown() {
int otherHeights = 0;
ViewGroup dropDownView;
LayoutParams hintParams;
if (this.mDropDownList == null) {
Context context = this.mContext;
this.mShowDropDownRunnable = new Runnable() {
public void run() {
View view = ListPopupWindow.this.getAnchorView();
if (view != null && view.getWindowToken() != null) {
ListPopupWindow.this.show();
}
}
};
this.mDropDownList = new DropDownListView(context, !this.mModal);
if (this.mDropDownListHighlight != null) {
this.mDropDownList.setSelector(this.mDropDownListHighlight);
}
this.mDropDownList.setAdapter(this.mAdapter);
this.mDropDownList.setOnItemClickListener(this.mItemClickListener);
this.mDropDownList.setFocusable(true);
this.mDropDownList.setFocusableInTouchMode(true);
this.mDropDownList.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
if (position != -1) {
DropDownListView dropDownList = ListPopupWindow.this.mDropDownList;
if (dropDownList != null) {
dropDownList.mListSelectionHidden = false;
}
}
}
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
this.mDropDownList.setOnScrollListener(this.mScrollListener);
if (this.mItemSelectedListener != null) {
this.mDropDownList.setOnItemSelectedListener(this.mItemSelectedListener);
}
dropDownView = this.mDropDownList;
View hintView = this.mPromptView;
if (hintView != null) {
int widthMode;
int widthSize;
ViewGroup hintContainer = new LinearLayout(context);
hintContainer.setOrientation(1);
hintParams = new LayoutParams(-1, 0, 1.0f);
switch (this.mPromptPosition) {
case 0:
hintContainer.addView(hintView);
hintContainer.addView(dropDownView, hintParams);
break;
case 1:
hintContainer.addView(dropDownView, hintParams);
hintContainer.addView(hintView);
break;
default:
Log.e(TAG, "Invalid hint position " + this.mPromptPosition);
break;
}
if (this.mDropDownWidth >= 0) {
widthMode = Integer.MIN_VALUE;
widthSize = this.mDropDownWidth;
} else {
widthMode = 0;
widthSize = 0;
}
hintView.measure(MeasureSpec.makeMeasureSpec(widthSize, widthMode), 0);
hintParams = (LayoutParams) hintView.getLayoutParams();
otherHeights = (hintView.getMeasuredHeight() + hintParams.topMargin) + hintParams.bottomMargin;
dropDownView = hintContainer;
}
this.mPopup.setContentView(dropDownView);
} else {
dropDownView = (ViewGroup) this.mPopup.getContentView();
View view = this.mPromptView;
if (view != null) {
hintParams = (LayoutParams) view.getLayoutParams();
otherHeights = (view.getMeasuredHeight() + hintParams.topMargin) + hintParams.bottomMargin;
}
}
int padding = 0;
Drawable background = this.mPopup.getBackground();
if (background != null) {
background.getPadding(this.mTempRect);
padding = this.mTempRect.top + this.mTempRect.bottom;
if (!this.mDropDownVerticalOffsetSet) {
this.mDropDownVerticalOffset = -this.mTempRect.top;
}
} else {
this.mTempRect.setEmpty();
}
int maxHeight = getMaxAvailableHeight(getAnchorView(), this.mDropDownVerticalOffset, this.mPopup.getInputMethodMode() == 2);
if (this.mDropDownAlwaysVisible || this.mDropDownHeight == -1) {
return maxHeight + padding;
}
int childWidthSpec;
switch (this.mDropDownWidth) {
case -2:
childWidthSpec = MeasureSpec.makeMeasureSpec(this.mContext.getResources().getDisplayMetrics().widthPixels - (this.mTempRect.left + this.mTempRect.right), Integer.MIN_VALUE);
break;
case -1:
childWidthSpec = MeasureSpec.makeMeasureSpec(this.mContext.getResources().getDisplayMetrics().widthPixels - (this.mTempRect.left + this.mTempRect.right), 1073741824);
break;
default:
childWidthSpec = MeasureSpec.makeMeasureSpec(this.mDropDownWidth, 1073741824);
break;
}
int listContent = this.mDropDownList.measureHeightOfChildrenCompat(childWidthSpec, 0, -1, maxHeight - otherHeights, -1);
if (listContent > 0) {
otherHeights += padding;
}
return listContent + otherHeights;
}
private static boolean isConfirmKey(int keyCode) {
return keyCode == 66 || keyCode == 23;
}
private void setPopupClipToScreenEnabled(boolean clip) {
if (sClipToWindowEnabledMethod != null) {
try {
sClipToWindowEnabledMethod.invoke(this.mPopup, new Object[]{Boolean.valueOf(clip)});
} catch (Exception e) {
Log.i(TAG, "Could not call setClipToScreenEnabled() on PopupWindow. Oh well.");
}
}
}
private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
if (sGetMaxAvailableHeightMethod != null) {
try {
return ((Integer) sGetMaxAvailableHeightMethod.invoke(this.mPopup, new Object[]{anchor, Integer.valueOf(yOffset), Boolean.valueOf(ignoreBottomDecorations)})).intValue();
} catch (Exception e) {
Log.i(TAG, "Could not call getMaxAvailableHeightMethod(View, int, boolean) on PopupWindow. Using the public version.");
}
}
return this.mPopup.getMaxAvailableHeight(anchor, yOffset);
}
}