michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.widget; michael@0: michael@0: import org.mozilla.gecko.GeckoApp; michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.util.HardwareUtils; michael@0: michael@0: import android.content.res.Resources; michael@0: import android.graphics.drawable.BitmapDrawable; michael@0: import android.os.Build; michael@0: import android.view.Gravity; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.view.ViewGroup; michael@0: import android.widget.ImageView; michael@0: import android.widget.LinearLayout; michael@0: import android.widget.PopupWindow; michael@0: import android.widget.RelativeLayout; michael@0: michael@0: public class ArrowPopup extends PopupWindow { michael@0: protected final GeckoApp mActivity; michael@0: michael@0: private View mAnchor; michael@0: private ImageView mArrow; michael@0: michael@0: private int mArrowWidth; michael@0: private int mYOffset; michael@0: michael@0: protected LinearLayout mContent; michael@0: protected boolean mInflated; michael@0: michael@0: public ArrowPopup(GeckoApp aActivity) { michael@0: this(aActivity, null); michael@0: } michael@0: michael@0: public ArrowPopup(GeckoApp activity, View anchor) { michael@0: super(activity); michael@0: mActivity = activity; michael@0: mAnchor = anchor; michael@0: michael@0: mInflated = false; michael@0: michael@0: final Resources res = activity.getResources(); michael@0: mArrowWidth = res.getDimensionPixelSize(R.dimen.menu_popup_arrow_width); michael@0: mYOffset = res.getDimensionPixelSize(R.dimen.menu_popup_arrow_offset); michael@0: michael@0: setAnimationStyle(R.style.PopupAnimation); michael@0: } michael@0: michael@0: public void setAnchor(View anchor) { michael@0: mAnchor = anchor; michael@0: } michael@0: michael@0: protected void init() { michael@0: setBackgroundDrawable(new BitmapDrawable()); michael@0: setOutsideTouchable(true); michael@0: michael@0: setWindowLayoutMode(HardwareUtils.isTablet() ? ViewGroup.LayoutParams.WRAP_CONTENT : ViewGroup.LayoutParams.FILL_PARENT, michael@0: ViewGroup.LayoutParams.WRAP_CONTENT); michael@0: michael@0: LayoutInflater inflater = LayoutInflater.from(mActivity); michael@0: RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.arrow_popup, null); michael@0: setContentView(layout); michael@0: michael@0: mArrow = (ImageView) layout.findViewById(R.id.arrow); michael@0: mContent = (LinearLayout) layout.findViewById(R.id.content); michael@0: michael@0: mInflated = true; michael@0: } michael@0: michael@0: /* michael@0: * Shows the popup with the arrow pointing to the center of the anchor view. If an anchor hasn't michael@0: * been set or isn't visible, the popup will just be shown at the top of the gecko app view. michael@0: */ michael@0: public void show() { michael@0: int[] anchorLocation = new int[2]; michael@0: if (mAnchor != null) michael@0: mAnchor.getLocationInWindow(anchorLocation); michael@0: michael@0: // If there's no anchor or the anchor is out of the window bounds, michael@0: // just show the popup at the top of the gecko app view. michael@0: if (mAnchor == null || anchorLocation[1] < 0) { michael@0: final View view = mActivity.getView(); michael@0: michael@0: // Bug in android code causes the window layout parameters to be ignored michael@0: // when using showAtLocation() in Gingerbread phones. michael@0: if (Build.VERSION.SDK_INT < 11) { michael@0: setWidth(view.getWidth()); michael@0: setHeight(view.getHeight()); michael@0: } michael@0: michael@0: showAtLocation(view, Gravity.TOP, 0, 0); michael@0: return; michael@0: } michael@0: michael@0: // Remove padding from the width of the anchor when calculating the arrow offset. michael@0: int anchorWidth = mAnchor.getWidth() - mAnchor.getPaddingLeft() - mAnchor.getPaddingRight(); michael@0: // This is the difference between the edge of the anchor view and the edge of the arrow view. michael@0: // We're making an assumption here that the anchor view is wider than the arrow view. michael@0: int arrowOffset = (anchorWidth - mArrowWidth)/2 + mAnchor.getPaddingLeft(); michael@0: michael@0: // The horizontal offset of the popup window, relative to the left side of the anchor view. michael@0: int offset = 0; michael@0: michael@0: RelativeLayout.LayoutParams arrowLayoutParams = (RelativeLayout.LayoutParams) mArrow.getLayoutParams(); michael@0: michael@0: if (HardwareUtils.isTablet()) { michael@0: // On tablets, the popup has a fixed width, so we use a horizontal offset to position it. michael@0: // The arrow's left margin is set by the arrow_popup.xml layout file. michael@0: // This assumes that anchor is not too close to the right side of the screen. michael@0: offset = arrowOffset - arrowLayoutParams.leftMargin; michael@0: } else { michael@0: // On phones, the popup takes up the width of the screen, so we set the arrow's left michael@0: // margin to make it line up with the anchor. michael@0: int leftMargin = anchorLocation[0] + arrowOffset; michael@0: arrowLayoutParams.setMargins(leftMargin, 0, 0, 0); michael@0: } michael@0: michael@0: if (isShowing()) { michael@0: update(mAnchor, offset, -mYOffset, -1, -1); michael@0: } else { michael@0: showAsDropDown(mAnchor, offset, -mYOffset); michael@0: } michael@0: } michael@0: }