summaryrefslogtreecommitdiffstats
path: root/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
diff options
context:
space:
mode:
Diffstat (limited to 'actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java')
-rw-r--r--actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java644
1 files changed, 0 insertions, 644 deletions
diff --git a/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java b/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
deleted file mode 100644
index d13c6cea9..000000000
--- a/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
+++ /dev/null
@@ -1,644 +0,0 @@
-package com.actionbarsherlock.internal.widget;
-
-import com.actionbarsherlock.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.DataSetObserver;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.PopupWindow;
-
-/**
- * A proxy between pre- and post-Honeycomb implementations of this class.
- */
-public class IcsListPopupWindow {
- /**
- * This value controls the length of time that the user
- * must leave a pointer down without scrolling to expand
- * the autocomplete dropdown list to cover the IME.
- */
- private static final int EXPAND_LIST_TIMEOUT = 250;
-
- private Context mContext;
- private PopupWindow mPopup;
- private ListAdapter mAdapter;
- private DropDownListView mDropDownList;
-
- private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
- private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
- private int mDropDownHorizontalOffset;
- private int mDropDownVerticalOffset;
- private boolean mDropDownVerticalOffsetSet;
-
- private int mListItemExpandMaximum = Integer.MAX_VALUE;
-
- private View mPromptView;
- private int mPromptPosition = POSITION_PROMPT_ABOVE;
-
- private DataSetObserver mObserver;
-
- private View mDropDownAnchorView;
-
- private Drawable mDropDownListHighlight;
-
- private AdapterView.OnItemClickListener mItemClickListener;
- private AdapterView.OnItemSelectedListener mItemSelectedListener;
-
- private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
- private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
- private final PopupScrollListener mScrollListener = new PopupScrollListener();
- private final ListSelectorHider mHideSelector = new ListSelectorHider();
-
- private Handler mHandler = new Handler();
-
- private Rect mTempRect = new Rect();
-
- private boolean mModal;
-
- public static final int POSITION_PROMPT_ABOVE = 0;
- public static final int POSITION_PROMPT_BELOW = 1;
-
- public IcsListPopupWindow(Context context) {
- this(context, null, R.attr.listPopupWindowStyle);
- }
-
- public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
- mContext = context;
- mPopup = new PopupWindow(context, attrs, defStyleAttr);
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- }
-
- public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- mContext = context;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- Context wrapped = new ContextThemeWrapper(context, defStyleRes);
- mPopup = new PopupWindow(wrapped, attrs, defStyleAttr);
- } else {
- mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
- }
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- }
-
- public void setAdapter(ListAdapter adapter) {
- if (mObserver == null) {
- mObserver = new PopupDataSetObserver();
- } else if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(mObserver);
- }
- mAdapter = adapter;
- if (mAdapter != null) {
- adapter.registerDataSetObserver(mObserver);
- }
-
- if (mDropDownList != null) {
- mDropDownList.setAdapter(mAdapter);
- }
- }
-
- public void setPromptPosition(int position) {
- mPromptPosition = position;
- }
-
- public void setModal(boolean modal) {
- mModal = true;
- mPopup.setFocusable(modal);
- }
-
- public void setBackgroundDrawable(Drawable d) {
- mPopup.setBackgroundDrawable(d);
- }
-
- public void setAnchorView(View anchor) {
- mDropDownAnchorView = anchor;
- }
-
- public void setHorizontalOffset(int offset) {
- mDropDownHorizontalOffset = offset;
- }
-
- public void setVerticalOffset(int offset) {
- mDropDownVerticalOffset = offset;
- mDropDownVerticalOffsetSet = true;
- }
-
- public void setContentWidth(int width) {
- Drawable popupBackground = mPopup.getBackground();
- if (popupBackground != null) {
- popupBackground.getPadding(mTempRect);
- mDropDownWidth = mTempRect.left + mTempRect.right + width;
- } else {
- mDropDownWidth = width;
- }
- }
-
- public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
- mItemClickListener = clickListener;
- }
-
- public void show() {
- int height = buildDropDown();
-
- int widthSpec = 0;
- int heightSpec = 0;
-
- boolean noInputMethod = isInputMethodNotNeeded();
- //XXX mPopup.setAllowScrollingAnchorParent(!noInputMethod);
-
- if (mPopup.isShowing()) {
- if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
- // The call to PopupWindow's update method below can accept -1 for any
- // value you do not want to update.
- widthSpec = -1;
- } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- widthSpec = mDropDownAnchorView.getWidth();
- } else {
- widthSpec = mDropDownWidth;
- }
-
- if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- // The call to PopupWindow's update method below can accept -1 for any
- // value you do not want to update.
- heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
- if (noInputMethod) {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
- } else {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0,
- ViewGroup.LayoutParams.MATCH_PARENT);
- }
- } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- heightSpec = height;
- } else {
- heightSpec = mDropDownHeight;
- }
-
- mPopup.setOutsideTouchable(true);
-
- mPopup.update(mDropDownAnchorView, mDropDownHorizontalOffset,
- mDropDownVerticalOffset, widthSpec, heightSpec);
- } else {
- if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
- widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
- } else {
- if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setWidth(mDropDownAnchorView.getWidth());
- } else {
- mPopup.setWidth(mDropDownWidth);
- }
- }
-
- if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
- } else {
- if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setHeight(height);
- } else {
- mPopup.setHeight(mDropDownHeight);
- }
- }
-
- mPopup.setWindowLayoutMode(widthSpec, heightSpec);
- //XXX mPopup.setClipToScreenEnabled(true);
-
- // use outside touchable to dismiss drop down when touching outside of it, so
- // only set this if the dropdown is not always visible
- mPopup.setOutsideTouchable(true);
- mPopup.setTouchInterceptor(mTouchInterceptor);
- mPopup.showAsDropDown(mDropDownAnchorView,
- mDropDownHorizontalOffset, mDropDownVerticalOffset);
- mDropDownList.setSelection(ListView.INVALID_POSITION);
-
- if (!mModal || mDropDownList.isInTouchMode()) {
- clearListSelection();
- }
- if (!mModal) {
- mHandler.post(mHideSelector);
- }
- }
- }
-
- public void dismiss() {
- mPopup.dismiss();
- if (mPromptView != null) {
- final ViewParent parent = mPromptView.getParent();
- if (parent instanceof ViewGroup) {
- final ViewGroup group = (ViewGroup) parent;
- group.removeView(mPromptView);
- }
- }
- mPopup.setContentView(null);
- mDropDownList = null;
- mHandler.removeCallbacks(mResizePopupRunnable);
- }
-
- public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
- mPopup.setOnDismissListener(listener);
- }
-
- public void setInputMethodMode(int mode) {
- mPopup.setInputMethodMode(mode);
- }
-
- public void clearListSelection() {
- final DropDownListView list = mDropDownList;
- if (list != null) {
- // WARNING: Please read the comment where mListSelectionHidden is declared
- list.mListSelectionHidden = true;
- //XXX list.hideSelector();
- list.requestLayout();
- }
- }
-
- public boolean isShowing() {
- return mPopup.isShowing();
- }
-
- private boolean isInputMethodNotNeeded() {
- return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
- }
-
- public ListView getListView() {
- return mDropDownList;
- }
-
- private int buildDropDown() {
- ViewGroup dropDownView;
- int otherHeights = 0;
-
- if (mDropDownList == null) {
- Context context = mContext;
-
- mDropDownList = new DropDownListView(context, !mModal);
- if (mDropDownListHighlight != null) {
- mDropDownList.setSelector(mDropDownListHighlight);
- }
- mDropDownList.setAdapter(mAdapter);
- mDropDownList.setOnItemClickListener(mItemClickListener);
- mDropDownList.setFocusable(true);
- mDropDownList.setFocusableInTouchMode(true);
- mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- public void onItemSelected(AdapterView<?> parent, View view,
- int position, long id) {
-
- if (position != -1) {
- DropDownListView dropDownList = mDropDownList;
-
- if (dropDownList != null) {
- dropDownList.mListSelectionHidden = false;
- }
- }
- }
-
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- mDropDownList.setOnScrollListener(mScrollListener);
-
- if (mItemSelectedListener != null) {
- mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
- }
-
- dropDownView = mDropDownList;
-
- View hintView = mPromptView;
- if (hintView != null) {
- // if an hint has been specified, we accomodate more space for it and
- // add a text view in the drop down menu, at the bottom of the list
- LinearLayout hintContainer = new LinearLayout(context);
- hintContainer.setOrientation(LinearLayout.VERTICAL);
-
- LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
- );
-
- switch (mPromptPosition) {
- case POSITION_PROMPT_BELOW:
- hintContainer.addView(dropDownView, hintParams);
- hintContainer.addView(hintView);
- break;
-
- case POSITION_PROMPT_ABOVE:
- hintContainer.addView(hintView);
- hintContainer.addView(dropDownView, hintParams);
- break;
-
- default:
- break;
- }
-
- // measure the hint's height to find how much more vertical space
- // we need to add to the drop down's height
- int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.UNSPECIFIED;
- hintView.measure(widthSpec, heightSpec);
-
- hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
- otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
- + hintParams.bottomMargin;
-
- dropDownView = hintContainer;
- }
-
- mPopup.setContentView(dropDownView);
- } else {
- dropDownView = (ViewGroup) mPopup.getContentView();
- final View view = mPromptView;
- if (view != null) {
- LinearLayout.LayoutParams hintParams =
- (LinearLayout.LayoutParams) view.getLayoutParams();
- otherHeights = view.getMeasuredHeight() + hintParams.topMargin
- + hintParams.bottomMargin;
- }
- }
-
- // getMaxAvailableHeight() subtracts the padding, so we put it back
- // to get the available height for the whole window
- int padding = 0;
- Drawable background = mPopup.getBackground();
- if (background != null) {
- background.getPadding(mTempRect);
- padding = mTempRect.top + mTempRect.bottom;
-
- // If we don't have an explicit vertical offset, determine one from the window
- // background so that content will line up.
- if (!mDropDownVerticalOffsetSet) {
- mDropDownVerticalOffset = -mTempRect.top;
- }
- }
-
- // Max height available on the screen for a popup.
- boolean ignoreBottomDecorations =
- mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
- final int maxHeight = /*mPopup.*/getMaxAvailableHeight(
- mDropDownAnchorView, mDropDownVerticalOffset, ignoreBottomDecorations);
-
- if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
- return maxHeight + padding;
- }
-
- final int listContent = /*mDropDownList.*/measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
- 0, -1/*ListView.NO_POSITION*/, maxHeight - otherHeights, -1);
- // add padding only if the list has items in it, that way we don't show
- // the popup if it is not needed
- if (listContent > 0) otherHeights += padding;
-
- return listContent + otherHeights;
- }
-
- private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
- final Rect displayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(displayFrame);
-
- final int[] anchorPos = new int[2];
- anchor.getLocationOnScreen(anchorPos);
-
- int bottomEdge = displayFrame.bottom;
- if (ignoreBottomDecorations) {
- Resources res = anchor.getContext().getResources();
- bottomEdge = res.getDisplayMetrics().heightPixels;
- }
- final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
- final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
-
- // anchorPos[1] is distance from anchor to top of screen
- int returnedHeight = Math.max(distanceToBottom, distanceToTop);
- if (mPopup.getBackground() != null) {
- mPopup.getBackground().getPadding(mTempRect);
- returnedHeight -= mTempRect.top + mTempRect.bottom;
- }
-
- return returnedHeight;
- }
-
- private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
- final int maxHeight, int disallowPartialChildPosition) {
-
- final ListAdapter adapter = mAdapter;
- if (adapter == null) {
- return mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
- }
-
- // Include the padding of the list
- int returnedHeight = mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
- final int dividerHeight = ((mDropDownList.getDividerHeight() > 0) && mDropDownList.getDivider() != null) ? mDropDownList.getDividerHeight() : 0;
- // The previous height value that was less than maxHeight and contained
- // no partial children
- int prevHeightWithoutPartialChild = 0;
- int i;
- View child;
-
- // mItemCount - 1 since endPosition parameter is inclusive
- endPosition = (endPosition == -1/*NO_POSITION*/) ? adapter.getCount() - 1 : endPosition;
-
- for (i = startPosition; i <= endPosition; ++i) {
- child = mAdapter.getView(i, null, mDropDownList);
- if (mDropDownList.getCacheColorHint() != 0) {
- child.setDrawingCacheBackgroundColor(mDropDownList.getCacheColorHint());
- }
-
- measureScrapChild(child, i, widthMeasureSpec);
-
- if (i > 0) {
- // Count the divider for all but one child
- returnedHeight += dividerHeight;
- }
-
- returnedHeight += child.getMeasuredHeight();
-
- if (returnedHeight >= maxHeight) {
- // We went over, figure out which height to return. If returnedHeight > maxHeight,
- // then the i'th position did not fit completely.
- return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
- && (i > disallowPartialChildPosition) // We've past the min pos
- && (prevHeightWithoutPartialChild > 0) // We have a prev height
- && (returnedHeight != maxHeight) // i'th child did not fit completely
- ? prevHeightWithoutPartialChild
- : maxHeight;
- }
-
- if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
- prevHeightWithoutPartialChild = returnedHeight;
- }
- }
-
- // At this point, we went through the range of children, and they each
- // completely fit, so return the returnedHeight
- return returnedHeight;
- }
- private void measureScrapChild(View child, int position, int widthMeasureSpec) {
- ListView.LayoutParams p = (ListView.LayoutParams) child.getLayoutParams();
- if (p == null) {
- p = new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0);
- child.setLayoutParams(p);
- }
- //XXX p.viewType = mAdapter.getItemViewType(position);
- //XXX p.forceAdd = true;
-
- int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
- mDropDownList.getPaddingLeft() + mDropDownList.getPaddingRight(), p.width);
- int lpHeight = p.height;
- int childHeightSpec;
- if (lpHeight > 0) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
- } else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- }
- child.measure(childWidthSpec, childHeightSpec);
- }
-
- private static class DropDownListView extends ListView {
- /*
- * WARNING: This is a workaround for a touch mode issue.
- *
- * Touch mode is propagated lazily to windows. This causes problems in
- * the following scenario:
- * - Type something in the AutoCompleteTextView and get some results
- * - Move down with the d-pad to select an item in the list
- * - Move up with the d-pad until the selection disappears
- * - Type more text in the AutoCompleteTextView *using the soft keyboard*
- * and get new results; you are now in touch mode
- * - The selection comes back on the first item in the list, even though
- * the list is supposed to be in touch mode
- *
- * Using the soft keyboard triggers the touch mode change but that change
- * is propagated to our window only after the first list layout, therefore
- * after the list attempts to resurrect the selection.
- *
- * The trick to work around this issue is to pretend the list is in touch
- * mode when we know that the selection should not appear, that is when
- * we know the user moved the selection away from the list.
- *
- * This boolean is set to true whenever we explicitly hide the list's
- * selection and reset to false whenever we know the user moved the
- * selection back to the list.
- *
- * When this boolean is true, isInTouchMode() returns true, otherwise it
- * returns super.isInTouchMode().
- */
- private boolean mListSelectionHidden;
-
- private boolean mHijackFocus;
-
- public DropDownListView(Context context, boolean hijackFocus) {
- super(context, null, /*com.android.internal.*/R.attr.dropDownListViewStyle);
- mHijackFocus = hijackFocus;
- // TODO: Add an API to control this
- setCacheColorHint(0); // Transparent, since the background drawable could be anything.
- }
-
- //XXX @Override
- //View obtainView(int position, boolean[] isScrap) {
- // View view = super.obtainView(position, isScrap);
-
- // if (view instanceof TextView) {
- // ((TextView) view).setHorizontallyScrolling(true);
- // }
-
- // return view;
- //}
-
- @Override
- public boolean isInTouchMode() {
- // WARNING: Please read the comment where mListSelectionHidden is declared
- return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
- }
-
- @Override
- public boolean hasWindowFocus() {
- return mHijackFocus || super.hasWindowFocus();
- }
-
- @Override
- public boolean isFocused() {
- return mHijackFocus || super.isFocused();
- }
-
- @Override
- public boolean hasFocus() {
- return mHijackFocus || super.hasFocus();
- }
- }
-
- private class PopupDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- if (isShowing()) {
- // Resize the popup to fit new content
- show();
- }
- }
-
- @Override
- public void onInvalidated() {
- dismiss();
- }
- }
-
- private class ListSelectorHider implements Runnable {
- public void run() {
- clearListSelection();
- }
- }
-
- private class ResizePopupRunnable implements Runnable {
- public void run() {
- if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
- mDropDownList.getChildCount() <= mListItemExpandMaximum) {
- mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
- show();
- }
- }
- }
-
- private class PopupTouchInterceptor implements OnTouchListener {
- public boolean onTouch(View v, MotionEvent event) {
- final int action = event.getAction();
- final int x = (int) event.getX();
- final int y = (int) event.getY();
-
- if (action == MotionEvent.ACTION_DOWN &&
- mPopup != null && mPopup.isShowing() &&
- (x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
- mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
- } else if (action == MotionEvent.ACTION_UP) {
- mHandler.removeCallbacks(mResizePopupRunnable);
- }
- return false;
- }
- }
-
- private class PopupScrollListener implements ListView.OnScrollListener {
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
-
- }
-
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
- !isInputMethodNotNeeded() && mPopup.getContentView() != null) {
- mHandler.removeCallbacks(mResizePopupRunnable);
- mResizePopupRunnable.run();
- }
- }
- }
-}