summaryrefslogtreecommitdiff
path: root/core/java/android/widget/PopupWindow.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/widget/PopupWindow.java
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/widget/PopupWindow.java')
-rw-r--r--core/java/android/widget/PopupWindow.java1218
1 files changed, 0 insertions, 1218 deletions
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
deleted file mode 100644
index 4a5cea1cb028..000000000000
--- a/core/java/android/widget/PopupWindow.java
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import com.android.internal.R;
-
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnScrollChangedListener;
-import android.view.View.OnTouchListener;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.IBinder;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-
-import java.lang.ref.WeakReference;
-
-/**
- * <p>A popup window that can be used to display an arbitrary view. The popup
- * windows is a floating container that appears on top of the current
- * activity.</p>
- *
- * @see android.widget.AutoCompleteTextView
- * @see android.widget.Spinner
- */
-public class PopupWindow {
- /**
- * Mode for {@link #setInputMethodMode(int): the requirements for the
- * input method should be based on the focusability of the popup. That is
- * if it is focusable than it needs to work with the input method, else
- * it doesn't.
- */
- public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
-
- /**
- * Mode for {@link #setInputMethodMode(int): this popup always needs to
- * work with an input method, regardless of whether it is focusable. This
- * means that it will always be displayed so that the user can also operate
- * the input method while it is shown.
- */
-
- public static final int INPUT_METHOD_NEEDED = 1;
-
- /**
- * Mode for {@link #setInputMethodMode(int): this popup never needs to
- * work with an input method, regardless of whether it is focusable. This
- * means that it will always be displayed to use as much space on the
- * screen as needed, regardless of whether this covers the input method.
- */
- public static final int INPUT_METHOD_NOT_NEEDED = 2;
-
- private final Context mContext;
- private final WindowManager mWindowManager;
-
- private boolean mIsShowing;
- private boolean mIsDropdown;
-
- private View mContentView;
- private View mPopupView;
- private boolean mFocusable;
- private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE;
- private boolean mTouchable = true;
- private boolean mOutsideTouchable = false;
- private boolean mClippingEnabled = true;
-
- private OnTouchListener mTouchInterceptor;
-
- private int mWidthMode;
- private int mWidth;
- private int mLastWidth;
- private int mHeightMode;
- private int mHeight;
- private int mLastHeight;
-
- private int mPopupWidth;
- private int mPopupHeight;
-
- private int[] mDrawingLocation = new int[2];
- private int[] mScreenLocation = new int[2];
- private Rect mTempRect = new Rect();
-
- private Drawable mBackground;
-
- private boolean mAboveAnchor;
-
- private OnDismissListener mOnDismissListener;
- private boolean mIgnoreCheekPress = false;
-
- private int mAnimationStyle = -1;
-
- private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
- com.android.internal.R.attr.state_above_anchor
- };
-
- private WeakReference<View> mAnchor;
- private OnScrollChangedListener mOnScrollChangedListener =
- new OnScrollChangedListener() {
- public void onScrollChanged() {
- View anchor = mAnchor.get();
- if (anchor != null && mPopupView != null) {
- WindowManager.LayoutParams p = (WindowManager.LayoutParams)
- mPopupView.getLayoutParams();
-
- mAboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff);
- update(p.x, p.y, -1, -1, true);
- }
- }
- };
- private int mAnchorXoff, mAnchorYoff;
-
- /**
- * <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
- *
- * <p>The popup does provide a background.</p>
- */
- public PopupWindow(Context context) {
- this(context, null);
- }
-
- /**
- * <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
- *
- * <p>The popup does provide a background.</p>
- */
- public PopupWindow(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.popupWindowStyle);
- }
-
- /**
- * <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
- *
- * <p>The popup does provide a background.</p>
- */
- public PopupWindow(Context context, AttributeSet attrs, int defStyle) {
- mContext = context;
- mWindowManager = (WindowManager)context.getSystemService(
- Context.WINDOW_SERVICE);
-
- TypedArray a =
- context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.PopupWindow, defStyle, 0);
-
- mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
-
- a.recycle();
- }
-
- /**
- * <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
- *
- * <p>The popup does not provide any background. This should be handled
- * by the content view.</p>
- */
- public PopupWindow() {
- this(null, 0, 0);
- }
-
- /**
- * <p>Create a new non focusable popup window which can display the
- * <tt>contentView</tt>. The dimension of the window are (0,0).</p>
- *
- * <p>The popup does not provide any background. This should be handled
- * by the content view.</p>
- *
- * @param contentView the popup's content
- */
- public PopupWindow(View contentView) {
- this(contentView, 0, 0);
- }
-
- /**
- * <p>Create a new empty, non focusable popup window. The dimension of the
- * window must be passed to this constructor.</p>
- *
- * <p>The popup does not provide any background. This should be handled
- * by the content view.</p>
- *
- * @param width the popup's width
- * @param height the popup's height
- */
- public PopupWindow(int width, int height) {
- this(null, width, height);
- }
-
- /**
- * <p>Create a new non focusable popup window which can display the
- * <tt>contentView</tt>. The dimension of the window must be passed to
- * this constructor.</p>
- *
- * <p>The popup does not provide any background. This should be handled
- * by the content view.</p>
- *
- * @param contentView the popup's content
- * @param width the popup's width
- * @param height the popup's height
- */
- public PopupWindow(View contentView, int width, int height) {
- this(contentView, width, height, false);
- }
-
- /**
- * <p>Create a new popup window which can display the <tt>contentView</tt>.
- * The dimension of the window must be passed to this constructor.</p>
- *
- * <p>The popup does not provide any background. This should be handled
- * by the content view.</p>
- *
- * @param contentView the popup's content
- * @param width the popup's width
- * @param height the popup's height
- * @param focusable true if the popup can be focused, false otherwise
- */
- public PopupWindow(View contentView, int width, int height,
- boolean focusable) {
- mContext = contentView.getContext();
- mWindowManager = (WindowManager)mContext.getSystemService(
- Context.WINDOW_SERVICE);
- setContentView(contentView);
- setWidth(width);
- setHeight(height);
- setFocusable(focusable);
- }
-
- /**
- * <p>Return the drawable used as the popup window's background.</p>
- *
- * @return the background drawable or null
- */
- public Drawable getBackground() {
- return mBackground;
- }
-
- /**
- * <p>Change the background drawable for this popup window. The background
- * can be set to null.</p>
- *
- * @param background the popup's background
- */
- public void setBackgroundDrawable(Drawable background) {
- mBackground = background;
- }
-
- /**
- * <p>Return the animation style to use the popup appears and disappears</p>
- *
- * @return the animation style to use the popup appears and disappears
- */
- public int getAnimationStyle() {
- return mAnimationStyle;
- }
-
- /**
- * Set the flag on popup to ignore cheek press eventt; by default this flag
- * is set to false
- * which means the pop wont ignore cheek press dispatch events.
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @see #update()
- */
- public void setIgnoreCheekPress() {
- mIgnoreCheekPress = true;
- }
-
-
- /**
- * <p>Change the animation style resource for this popup.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @param animationStyle animation style to use when the popup appears
- * and disappears. Set to -1 for the default animation, 0 for no
- * animation, or a resource identifier for an explicit animation.
- *
- * @see #update()
- */
- public void setAnimationStyle(int animationStyle) {
- mAnimationStyle = animationStyle;
- }
-
- /**
- * <p>Return the view used as the content of the popup window.</p>
- *
- * @return a {@link android.view.View} representing the popup's content
- *
- * @see #setContentView(android.view.View)
- */
- public View getContentView() {
- return mContentView;
- }
-
- /**
- * <p>Change the popup's content. The content is represented by an instance
- * of {@link android.view.View}.</p>
- *
- * <p>This method has no effect if called when the popup is showing. To
- * apply it while a popup is showing, call </p>
- *
- * @param contentView the new content for the popup
- *
- * @see #getContentView()
- * @see #isShowing()
- */
- public void setContentView(View contentView) {
- if (isShowing()) {
- return;
- }
-
- mContentView = contentView;
- }
-
- /**
- * Set a callback for all touch events being dispatched to the popup
- * window.
- */
- public void setTouchInterceptor(OnTouchListener l) {
- mTouchInterceptor = l;
- }
-
- /**
- * <p>Indicate whether the popup window can grab the focus.</p>
- *
- * @return true if the popup is focusable, false otherwise
- *
- * @see #setFocusable(boolean)
- */
- public boolean isFocusable() {
- return mFocusable;
- }
-
- /**
- * <p>Changes the focusability of the popup window. When focusable, the
- * window will grab the focus from the current focused widget if the popup
- * contains a focusable {@link android.view.View}. By default a popup
- * window is not focusable.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @param focusable true if the popup should grab focus, false otherwise.
- *
- * @see #isFocusable()
- * @see #isShowing()
- * @see #update()
- */
- public void setFocusable(boolean focusable) {
- mFocusable = focusable;
- }
-
- /**
- * Return the current value in {@link #setInputMethodMode(int)}.
- *
- * @see #setInputMethodMode(int)
- */
- public int getInputMethodMode() {
- return mInputMethodMode;
-
- }
-
- /**
- * Control how the popup operates with an input method: one of
- * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
- * or {@link #INPUT_METHOD_NOT_NEEDED}.
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @see #getInputMethodMode()
- * @see #update()
- */
- public void setInputMethodMode(int mode) {
- mInputMethodMode = mode;
- }
-
- /**
- * <p>Indicates whether the popup window receives touch events.</p>
- *
- * @return true if the popup is touchable, false otherwise
- *
- * @see #setTouchable(boolean)
- */
- public boolean isTouchable() {
- return mTouchable;
- }
-
- /**
- * <p>Changes the touchability of the popup window. When touchable, the
- * window will receive touch events, otherwise touch events will go to the
- * window below it. By default the window is touchable.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @param touchable true if the popup should receive touch events, false otherwise
- *
- * @see #isTouchable()
- * @see #isShowing()
- * @see #update()
- */
- public void setTouchable(boolean touchable) {
- mTouchable = touchable;
- }
-
- /**
- * <p>Indicates whether the popup window will be informed of touch events
- * outside of its window.</p>
- *
- * @return true if the popup is outside touchable, false otherwise
- *
- * @see #setOutsideTouchable(boolean)
- */
- public boolean isOutsideTouchable() {
- return mOutsideTouchable;
- }
-
- /**
- * <p>Controls whether the pop-up will be informed of touch events outside
- * of its window. This only makes sense for pop-ups that are touchable
- * but not focusable, which means touches outside of the window will
- * be delivered to the window behind. The default is false.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @param touchable true if the popup should receive outside
- * touch events, false otherwise
- *
- * @see #isOutsideTouchable()
- * @see #isShowing()
- * @see #update()
- */
- public void setOutsideTouchable(boolean touchable) {
- mOutsideTouchable = touchable;
- }
-
- /**
- * <p>Indicates whether clipping of the popup window is enabled.</p>
- *
- * @return true if the clipping is enabled, false otherwise
- *
- * @see #setClippingEnabled(boolean)
- */
- public boolean isClippingEnabled() {
- return mClippingEnabled;
- }
-
- /**
- * <p>Allows the popup window to extend beyond the bounds of the screen. By default the
- * window is clipped to the screen boundaries. Setting this to false will allow windows to be
- * accurately positioned.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown or through a manual call to one of
- * the {@link #update()} methods.</p>
- *
- * @param enabled false if the window should be allowed to extend outside of the screen
- * @see #isShowing()
- * @see #isClippingEnabled()
- * @see #update()
- */
- public void setClippingEnabled(boolean enabled) {
- mClippingEnabled = enabled;
- }
-
- /**
- * <p>Change the width and height measure specs that are given to the
- * window manager by the popup. By default these are 0, meaning that
- * the current width or height is requested as an explicit size from
- * the window manager. You can supply
- * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or
- * {@link ViewGroup.LayoutParams#FILL_PARENT} to have that measure
- * spec supplied instead, replacing the absolute width and height that
- * has been set in the popup.</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown.</p>
- *
- * @param widthSpec an explicit width measure spec mode, either
- * {@link ViewGroup.LayoutParams#WRAP_CONTENT},
- * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute
- * width.
- * @param heightSpec an explicit height measure spec mode, either
- * {@link ViewGroup.LayoutParams#WRAP_CONTENT},
- * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute
- * height.
- */
- public void setWindowLayoutMode(int widthSpec, int heightSpec) {
- mWidthMode = widthSpec;
- mHeightMode = heightSpec;
- }
-
- /**
- * <p>Return this popup's height MeasureSpec</p>
- *
- * @return the height MeasureSpec of the popup
- *
- * @see #setHeight(int)
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * <p>Change the popup's height MeasureSpec</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown.</p>
- *
- * @param height the height MeasureSpec of the popup
- *
- * @see #getHeight()
- * @see #isShowing()
- */
- public void setHeight(int height) {
- mHeight = height;
- }
-
- /**
- * <p>Return this popup's width MeasureSpec</p>
- *
- * @return the width MeasureSpec of the popup
- *
- * @see #setWidth(int)
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * <p>Change the popup's width MeasureSpec</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown.</p>
- *
- * @param width the width MeasureSpec of the popup
- *
- * @see #getWidth()
- * @see #isShowing()
- */
- public void setWidth(int width) {
- mWidth = width;
- }
-
- /**
- * <p>Indicate whether this popup window is showing on screen.</p>
- *
- * @return true if the popup is showing, false otherwise
- */
- public boolean isShowing() {
- return mIsShowing;
- }
-
- /**
- * <p>
- * Display the content view in a popup window at the specified location. If the popup window
- * cannot fit on screen, it will be clipped. See {@link android.view.WindowManager.LayoutParams}
- * for more information on how gravity and the x and y parameters are related. Specifying
- * a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
- * <code>Gravity.LEFT | Gravity.TOP</code>.
- * </p>
- *
- * @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
- * @param gravity the gravity which controls the placement of the popup window
- * @param x the popup's x location offset
- * @param y the popup's y location offset
- */
- public void showAtLocation(View parent, int gravity, int x, int y) {
- if (isShowing() || mContentView == null) {
- return;
- }
-
- unregisterForScrollChanged();
-
- mIsShowing = true;
- mIsDropdown = false;
-
- WindowManager.LayoutParams p = createPopupLayout(parent.getWindowToken());
- p.windowAnimations = computeAnimationResource();
-
- preparePopup(p);
- if (gravity == Gravity.NO_GRAVITY) {
- gravity = Gravity.TOP | Gravity.LEFT;
- }
- p.gravity = gravity;
- p.x = x;
- p.y = y;
- invokePopup(p);
- }
-
- /**
- * <p>Display the content view in a popup window anchored to the bottom-left
- * corner of the anchor view. If there is not enough room on screen to show
- * the popup in its entirety, this method tries to find a parent scroll
- * view to scroll. If no parent scroll view can be scrolled, the bottom-left
- * corner of the popup is pinned at the top left corner of the anchor view.</p>
- *
- * @param anchor the view on which to pin the popup window
- *
- * @see #dismiss()
- */
- public void showAsDropDown(View anchor) {
- showAsDropDown(anchor, 0, 0);
- }
-
- /**
- * <p>Display the content view in a popup window anchored to the bottom-left
- * corner of the anchor view offset by the specified x and y coordinates.
- * If there is not enough room on screen to show
- * the popup in its entirety, this method tries to find a parent scroll
- * view to scroll. If no parent scroll view can be scrolled, the bottom-left
- * corner of the popup is pinned at the top left corner of the anchor view.</p>
- * <p>If the view later scrolls to move <code>anchor</code> to a different
- * location, the popup will be moved correspondingly.</p>
- *
- * @param anchor the view on which to pin the popup window
- *
- * @see #dismiss()
- */
- public void showAsDropDown(View anchor, int xoff, int yoff) {
- if (isShowing() || mContentView == null) {
- return;
- }
-
- registerForScrollChanged(anchor, xoff, yoff);
-
- mIsShowing = true;
- mIsDropdown = true;
-
- WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
- preparePopup(p);
- mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
-
- if (mBackground != null) {
- mPopupView.refreshDrawableState();
- }
-
- if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
- if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
-
- p.windowAnimations = computeAnimationResource();
-
- invokePopup(p);
- }
-
- /**
- * Indicates whether the popup is showing above (the y coordinate of the popup's bottom
- * is less than the y coordinate of the anchor) or below the anchor view (the y coordinate
- * of the popup is greater than y coordinate of the anchor's bottom).
- *
- * The value returned
- * by this method is meaningful only after {@link #showAsDropDown(android.view.View)}
- * or {@link #showAsDropDown(android.view.View, int, int)} was invoked.
- *
- * @return True if this popup is showing above the anchor view, false otherwise.
- */
- public boolean isAboveAnchor() {
- return mAboveAnchor;
- }
-
- /**
- * <p>Prepare the popup by embedding in into a new ViewGroup if the
- * background drawable is not null. If embedding is required, the layout
- * parameters' height is mnodified to take into account the background's
- * padding.</p>
- *
- * @param p the layout parameters of the popup's content view
- */
- private void preparePopup(WindowManager.LayoutParams p) {
- if (mBackground != null) {
- // when a background is available, we embed the content view
- // within another view that owns the background drawable
- PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
- PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT
- );
- popupViewContainer.setBackgroundDrawable(mBackground);
- popupViewContainer.addView(mContentView, listParams);
-
- mPopupView = popupViewContainer;
- } else {
- mPopupView = mContentView;
- }
- mPopupWidth = p.width;
- mPopupHeight = p.height;
- }
-
- /**
- * <p>Invoke the popup window by adding the content view to the window
- * manager.</p>
- *
- * <p>The content view must be non-null when this method is invoked.</p>
- *
- * @param p the layout parameters of the popup's content view
- */
- private void invokePopup(WindowManager.LayoutParams p) {
- mWindowManager.addView(mPopupView, p);
- }
-
- /**
- * <p>Generate the layout parameters for the popup window.</p>
- *
- * @param token the window token used to bind the popup's window
- *
- * @return the layout parameters to pass to the window manager
- */
- private WindowManager.LayoutParams createPopupLayout(IBinder token) {
- // generates the layout parameters for the drop down
- // we want a fixed size view located at the bottom left of the anchor
- WindowManager.LayoutParams p = new WindowManager.LayoutParams();
- // these gravity settings put the view at the top left corner of the
- // screen. The view is then positioned to the appropriate location
- // by setting the x and y offsets to match the anchor's bottom
- // left corner
- p.gravity = Gravity.LEFT | Gravity.TOP;
- p.width = mLastWidth = mWidth;
- p.height = mLastHeight = mHeight;
- if (mBackground != null) {
- p.format = mBackground.getOpacity();
- } else {
- p.format = PixelFormat.TRANSLUCENT;
- }
- p.flags = computeFlags(p.flags);
- p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
- p.token = token;
- p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
-
- return p;
- }
-
- private int computeFlags(int curFlags) {
- curFlags &= ~(
- WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES |
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
- WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
- WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
- if(mIgnoreCheekPress) {
- curFlags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
- }
- if (!mFocusable) {
- curFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- if (mInputMethodMode == INPUT_METHOD_NEEDED) {
- curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- } else if (mInputMethodMode == INPUT_METHOD_NOT_NEEDED) {
- curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- if (!mTouchable) {
- curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
- }
- if (mTouchable) {
- curFlags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
- }
- if (!mClippingEnabled) {
- curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
- }
- return curFlags;
- }
-
- private int computeAnimationResource() {
- if (mAnimationStyle == -1) {
- if (mIsDropdown) {
- return mAboveAnchor
- ? com.android.internal.R.style.Animation_DropDownUp
- : com.android.internal.R.style.Animation_DropDownDown;
- }
- return 0;
- }
- return mAnimationStyle;
- }
-
- /**
- * <p>Positions the popup window on screen. When the popup window is too
- * tall to fit under the anchor, a parent scroll view is seeked and scrolled
- * up to reclaim space. If scrolling is not possible or not enough, the
- * popup window gets moved on top of the anchor.</p>
- *
- * <p>The height must have been set on the layout parameters prior to
- * calling this method.</p>
- *
- * @param anchor the view on which the popup window must be anchored
- * @param p the layout parameters used to display the drop down
- *
- * @return true if the popup is translated upwards to fit on screen
- */
- private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
- int xoff, int yoff) {
-
- anchor.getLocationInWindow(mDrawingLocation);
- p.x = mDrawingLocation[0] + xoff;
- p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
-
- boolean onTop = false;
-
- p.gravity = Gravity.LEFT | Gravity.TOP;
-
- anchor.getLocationOnScreen(mScreenLocation);
- final Rect displayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(displayFrame);
-
- final View root = anchor.getRootView();
- if (p.y + mPopupHeight > displayFrame.bottom || p.x + mPopupWidth - root.getWidth() > 0) {
- // if the drop down disappears at the bottom of the screen. we try to
- // scroll a parent scrollview or move the drop down back up on top of
- // the edit box
- int scrollX = anchor.getScrollX();
- int scrollY = anchor.getScrollY();
- Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth,
- scrollY + mPopupHeight + anchor.getMeasuredHeight());
- anchor.requestRectangleOnScreen(r, true);
-
- // now we re-evaluate the space available, and decide from that
- // whether the pop-up will go above or below the anchor.
- anchor.getLocationInWindow(mDrawingLocation);
- p.x = mDrawingLocation[0] + xoff;
- p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
-
- // determine whether there is more space above or below the anchor
- anchor.getLocationOnScreen(mScreenLocation);
-
- onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff) <
- (mScreenLocation[1] - yoff - displayFrame.top);
- if (onTop) {
- p.gravity = Gravity.LEFT | Gravity.BOTTOM;
- p.y = root.getHeight() - mDrawingLocation[1] + yoff;
- } else {
- p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
- }
- }
-
- p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
-
- return onTop;
- }
-
- /**
- * Returns the maximum height that is available for the popup to be
- * completely shown. It is recommended that this height be the maximum for
- * the popup's height, otherwise it is possible that the popup will be
- * clipped.
- *
- * @param anchor The view on which the popup window must be anchored.
- * @return The maximum available height for the popup to be completely
- * shown.
- */
- public int getMaxAvailableHeight(View anchor) {
- return getMaxAvailableHeight(anchor, 0);
- }
-
- /**
- * Returns the maximum height that is available for the popup to be
- * completely shown. It is recommended that this height be the maximum for
- * the popup's height, otherwise it is possible that the popup will be
- * clipped.
- *
- * @param anchor The view on which the popup window must be anchored.
- * @param yOffset y offset from the view's bottom edge
- * @return The maximum available height for the popup to be completely
- * shown.
- */
- public int getMaxAvailableHeight(View anchor, int yOffset) {
- final Rect displayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(displayFrame);
-
- final int[] anchorPos = mDrawingLocation;
- anchor.getLocationOnScreen(anchorPos);
-
- final int distanceToBottom = displayFrame.bottom -
- (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 (mBackground != null) {
- mBackground.getPadding(mTempRect);
- returnedHeight -= mTempRect.top + mTempRect.bottom;
- }
-
- return returnedHeight;
- }
-
- /**
- * <p>Dispose of the popup window. This method can be invoked only after
- * {@link #showAsDropDown(android.view.View)} has been executed. Failing that, calling
- * this method will have no effect.</p>
- *
- * @see #showAsDropDown(android.view.View)
- */
- public void dismiss() {
- if (isShowing() && mPopupView != null) {
- unregisterForScrollChanged();
-
- mWindowManager.removeView(mPopupView);
- if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
- ((ViewGroup) mPopupView).removeView(mContentView);
- }
- mPopupView = null;
- mIsShowing = false;
-
- if (mOnDismissListener != null) {
- mOnDismissListener.onDismiss();
- }
- }
- }
-
- /**
- * Sets the listener to be called when the window is dismissed.
- *
- * @param onDismissListener The listener.
- */
- public void setOnDismissListener(OnDismissListener onDismissListener) {
- mOnDismissListener = onDismissListener;
- }
-
- /**
- * Updates the state of the popup window, if it is currently being displayed,
- * from the currently set state. This include:
- * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)},
- * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)},
- * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}.
- */
- public void update() {
- if (!isShowing() || mContentView == null) {
- return;
- }
-
- WindowManager.LayoutParams p = (WindowManager.LayoutParams)
- mPopupView.getLayoutParams();
-
- boolean update = false;
-
- final int newAnim = computeAnimationResource();
- if (newAnim != p.windowAnimations) {
- p.windowAnimations = newAnim;
- update = true;
- }
-
- final int newFlags = computeFlags(p.flags);
- if (newFlags != p.flags) {
- p.flags = newFlags;
- update = true;
- }
-
- if (update) {
- mWindowManager.updateViewLayout(mPopupView, p);
- }
- }
-
- /**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
- *
- * @param x the new x location
- * @param y the new y location
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
- */
- public void update(int x, int y, int width, int height) {
- update(x, y, width, height, false);
- }
-
- /**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
- *
- * @param x the new x location
- * @param y the new y location
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
- * @param force reposition the window even if the specified position
- * already seems to correspond to the LayoutParams
- *
- * @hide pending API council approval
- */
- public void update(int x, int y, int width, int height, boolean force) {
- if (width != -1) {
- mLastWidth = width;
- setWidth(width);
- }
-
- if (height != -1) {
- mLastHeight = height;
- setHeight(height);
- }
-
- if (!isShowing() || mContentView == null) {
- return;
- }
-
- WindowManager.LayoutParams p = (WindowManager.LayoutParams)
- mPopupView.getLayoutParams();
-
- boolean update = force;
-
- final int finalWidth = mWidthMode < 0 ? mWidthMode : mLastWidth;
- if (width != -1 && p.width != finalWidth) {
- p.width = mLastWidth = finalWidth;
- update = true;
- }
-
- final int finalHeight = mHeightMode < 0 ? mHeightMode : mLastHeight;
- if (height != -1 && p.height != finalHeight) {
- p.height = mLastHeight = finalHeight;
- update = true;
- }
-
- if (p.x != x) {
- p.x = x;
- update = true;
- }
-
- if (p.y != y) {
- p.y = y;
- update = true;
- }
-
- final int newAnim = computeAnimationResource();
- if (newAnim != p.windowAnimations) {
- p.windowAnimations = newAnim;
- update = true;
- }
-
- final int newFlags = computeFlags(p.flags);
- if (newFlags != p.flags) {
- p.flags = newFlags;
- update = true;
- }
-
- if (update) {
- mWindowManager.updateViewLayout(mPopupView, p);
- }
- }
-
- /**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
- *
- * @param anchor the popup's anchor view
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
- */
- public void update(View anchor, int width, int height) {
- update(anchor, 0, 0, width, height);
- }
-
- /**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
- * <p>If the view later scrolls to move <code>anchor</code> to a different
- * location, the popup will be moved correspondingly.</p>
- *
- * @param anchor the popup's anchor view
- * @param xoff x offset from the view's left edge
- * @param yoff y offset from the view's bottom edge
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
- */
- public void update(View anchor, int xoff, int yoff, int width, int height) {
- if (!isShowing() || mContentView == null) {
- return;
- }
-
- WeakReference<View> oldAnchor = mAnchor;
- if (oldAnchor == null || oldAnchor.get() != anchor ||
- mAnchorXoff != xoff || mAnchorYoff != yoff) {
- registerForScrollChanged(anchor, xoff, yoff);
- }
-
- WindowManager.LayoutParams p = (WindowManager.LayoutParams)
- mPopupView.getLayoutParams();
-
- if (width == -1) {
- width = mPopupWidth;
- } else {
- mPopupWidth = width;
- }
- if (height == -1) {
- height = mPopupHeight;
- } else {
- mPopupHeight = height;
- }
-
- mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
- update(p.x, p.y, width, height);
- }
-
- /**
- * Listener that is called when this popup window is dismissed.
- */
- public interface OnDismissListener {
- /**
- * Called when this popup window is dismissed.
- */
- public void onDismiss();
- }
-
- private void unregisterForScrollChanged() {
- WeakReference<View> anchorRef = mAnchor;
- View anchor = null;
- if (anchorRef != null) {
- anchor = anchorRef.get();
- }
- if (anchor != null) {
- ViewTreeObserver vto = anchor.getViewTreeObserver();
- vto.removeOnScrollChangedListener(mOnScrollChangedListener);
- }
- mAnchor = null;
- }
-
- private void registerForScrollChanged(View anchor, int xoff, int yoff) {
- unregisterForScrollChanged();
-
- mAnchor = new WeakReference<View>(anchor);
- ViewTreeObserver vto = anchor.getViewTreeObserver();
- if (vto != null) {
- vto.addOnScrollChangedListener(mOnScrollChangedListener);
- }
-
- mAnchorXoff = xoff;
- mAnchorYoff = yoff;
- }
-
- private class PopupViewContainer extends FrameLayout {
-
- public PopupViewContainer(Context context) {
- super(context);
- }
-
- @Override
- protected int[] onCreateDrawableState(int extraSpace) {
- if (mAboveAnchor) {
- // 1 more needed for the above anchor state
- final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
- View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET);
- return drawableState;
- } else {
- return super.onCreateDrawableState(extraSpace);
- }
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- dismiss();
- return true;
- } else {
- return super.dispatchKeyEvent(event);
- }
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) {
- return true;
- }
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final int x = (int) event.getX();
- final int y = (int) event.getY();
-
- if ((event.getAction() == MotionEvent.ACTION_DOWN)
- && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
- dismiss();
- return true;
- } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- dismiss();
- return true;
- } else {
- return super.onTouchEvent(event);
- }
- }
-
- }
-
-}