1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/widget/ArrowPopup.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,129 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.widget; 1.10 + 1.11 +import org.mozilla.gecko.GeckoApp; 1.12 +import org.mozilla.gecko.R; 1.13 +import org.mozilla.gecko.util.HardwareUtils; 1.14 + 1.15 +import android.content.res.Resources; 1.16 +import android.graphics.drawable.BitmapDrawable; 1.17 +import android.os.Build; 1.18 +import android.view.Gravity; 1.19 +import android.view.LayoutInflater; 1.20 +import android.view.View; 1.21 +import android.view.ViewGroup; 1.22 +import android.widget.ImageView; 1.23 +import android.widget.LinearLayout; 1.24 +import android.widget.PopupWindow; 1.25 +import android.widget.RelativeLayout; 1.26 + 1.27 +public class ArrowPopup extends PopupWindow { 1.28 + protected final GeckoApp mActivity; 1.29 + 1.30 + private View mAnchor; 1.31 + private ImageView mArrow; 1.32 + 1.33 + private int mArrowWidth; 1.34 + private int mYOffset; 1.35 + 1.36 + protected LinearLayout mContent; 1.37 + protected boolean mInflated; 1.38 + 1.39 + public ArrowPopup(GeckoApp aActivity) { 1.40 + this(aActivity, null); 1.41 + } 1.42 + 1.43 + public ArrowPopup(GeckoApp activity, View anchor) { 1.44 + super(activity); 1.45 + mActivity = activity; 1.46 + mAnchor = anchor; 1.47 + 1.48 + mInflated = false; 1.49 + 1.50 + final Resources res = activity.getResources(); 1.51 + mArrowWidth = res.getDimensionPixelSize(R.dimen.menu_popup_arrow_width); 1.52 + mYOffset = res.getDimensionPixelSize(R.dimen.menu_popup_arrow_offset); 1.53 + 1.54 + setAnimationStyle(R.style.PopupAnimation); 1.55 + } 1.56 + 1.57 + public void setAnchor(View anchor) { 1.58 + mAnchor = anchor; 1.59 + } 1.60 + 1.61 + protected void init() { 1.62 + setBackgroundDrawable(new BitmapDrawable()); 1.63 + setOutsideTouchable(true); 1.64 + 1.65 + setWindowLayoutMode(HardwareUtils.isTablet() ? ViewGroup.LayoutParams.WRAP_CONTENT : ViewGroup.LayoutParams.FILL_PARENT, 1.66 + ViewGroup.LayoutParams.WRAP_CONTENT); 1.67 + 1.68 + LayoutInflater inflater = LayoutInflater.from(mActivity); 1.69 + RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.arrow_popup, null); 1.70 + setContentView(layout); 1.71 + 1.72 + mArrow = (ImageView) layout.findViewById(R.id.arrow); 1.73 + mContent = (LinearLayout) layout.findViewById(R.id.content); 1.74 + 1.75 + mInflated = true; 1.76 + } 1.77 + 1.78 + /* 1.79 + * Shows the popup with the arrow pointing to the center of the anchor view. If an anchor hasn't 1.80 + * been set or isn't visible, the popup will just be shown at the top of the gecko app view. 1.81 + */ 1.82 + public void show() { 1.83 + int[] anchorLocation = new int[2]; 1.84 + if (mAnchor != null) 1.85 + mAnchor.getLocationInWindow(anchorLocation); 1.86 + 1.87 + // If there's no anchor or the anchor is out of the window bounds, 1.88 + // just show the popup at the top of the gecko app view. 1.89 + if (mAnchor == null || anchorLocation[1] < 0) { 1.90 + final View view = mActivity.getView(); 1.91 + 1.92 + // Bug in android code causes the window layout parameters to be ignored 1.93 + // when using showAtLocation() in Gingerbread phones. 1.94 + if (Build.VERSION.SDK_INT < 11) { 1.95 + setWidth(view.getWidth()); 1.96 + setHeight(view.getHeight()); 1.97 + } 1.98 + 1.99 + showAtLocation(view, Gravity.TOP, 0, 0); 1.100 + return; 1.101 + } 1.102 + 1.103 + // Remove padding from the width of the anchor when calculating the arrow offset. 1.104 + int anchorWidth = mAnchor.getWidth() - mAnchor.getPaddingLeft() - mAnchor.getPaddingRight(); 1.105 + // This is the difference between the edge of the anchor view and the edge of the arrow view. 1.106 + // We're making an assumption here that the anchor view is wider than the arrow view. 1.107 + int arrowOffset = (anchorWidth - mArrowWidth)/2 + mAnchor.getPaddingLeft(); 1.108 + 1.109 + // The horizontal offset of the popup window, relative to the left side of the anchor view. 1.110 + int offset = 0; 1.111 + 1.112 + RelativeLayout.LayoutParams arrowLayoutParams = (RelativeLayout.LayoutParams) mArrow.getLayoutParams(); 1.113 + 1.114 + if (HardwareUtils.isTablet()) { 1.115 + // On tablets, the popup has a fixed width, so we use a horizontal offset to position it. 1.116 + // The arrow's left margin is set by the arrow_popup.xml layout file. 1.117 + // This assumes that anchor is not too close to the right side of the screen. 1.118 + offset = arrowOffset - arrowLayoutParams.leftMargin; 1.119 + } else { 1.120 + // On phones, the popup takes up the width of the screen, so we set the arrow's left 1.121 + // margin to make it line up with the anchor. 1.122 + int leftMargin = anchorLocation[0] + arrowOffset; 1.123 + arrowLayoutParams.setMargins(leftMargin, 0, 0, 0); 1.124 + } 1.125 + 1.126 + if (isShowing()) { 1.127 + update(mAnchor, offset, -mYOffset, -1, -1); 1.128 + } else { 1.129 + showAsDropDown(mAnchor, offset, -mYOffset); 1.130 + } 1.131 + } 1.132 +}