Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(578)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/widget/TextBubble.java

Issue 810853003: Upstream FullscreenManager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comments Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.widget;
6
7 import android.content.Context;
8 import android.graphics.Canvas;
9 import android.graphics.ColorFilter;
10 import android.graphics.PixelFormat;
11 import android.graphics.Rect;
12 import android.graphics.drawable.BitmapDrawable;
13 import android.graphics.drawable.Drawable;
14 import android.os.Bundle;
15 import android.view.Gravity;
16 import android.view.View;
17 import android.view.View.MeasureSpec;
18 import android.view.View.OnAttachStateChangeListener;
19 import android.view.View.OnLayoutChangeListener;
20 import android.view.ViewGroup;
21 import android.widget.PopupWindow;
22 import android.widget.TextView;
23
24 import org.chromium.chrome.R;
25 import org.chromium.ui.base.LocalizationUtils;
26
27 /**
28 * UI component that handles showing text bubbles.
29 */
30 public class TextBubble
31 extends PopupWindow implements OnLayoutChangeListener, OnAttachStateChan geListener {
32 /** Whether to use the intrinsic padding of the bubble background as padding (boolean). */
33 public static final String BACKGROUND_INTRINSIC_PADDING = "Background_Intrin sic_Padding";
34
35 /**
36 * Boolean to be used for deciding whether the bubble should be anchored abo ve or below
37 * the view
38 */
39 public static final String UP_DOWN = "Up_Down";
40
41 /** Style resource Id to be used for text inside the bubble. Should be of ty pe int. */
42 public static final String TEXT_STYLE_ID = "Text_Style_Id";
43
44 /** Boolean to be used for deciding whether the bubble should be centered to the view */
45 public static final String CENTER = "Center";
46
47 public static final String ANIM_STYLE_ID = "Animation_Style";
48
49 private final int mTooltipEdgeMargin;
50 private final int mTooltipTopMargin;
51 private final int mBubbleTipXMargin;
52 private boolean mAnchorBelow = false;
53 private boolean mCenterView = true;
54 private int mXPosition;
55 private int mYPosition;
56 private View mAnchorView;
57 private final Rect mCachedPaddingRect = new Rect();
58
59 // The text view inside the popup containing the tooltip text.
60 private final TextView mTooltipText;
61
62 /**
63 * Constructor that uses a bundle object to fetch resources and optional boo lean
64 * values for the {@link TextBubble}.
65 *
66 * Use CENTER for centering the tip to the anchor view.
67 * UP_DOWN for drawing the bubble with tip pointing up or down.
68 * Up is true and Down is false.
69 * LAYOUT_WIDTH_ID Dimension resource Id for the width of the {@link Te xtView} inside the
70 * bubble. The height is set to half of this value.
71 *
72 * @param context
73 * @param res Bundle object that contains resource ids and optional flags.
74 */
75 public TextBubble(Context context, Bundle res) {
76 mAnchorBelow = (res.containsKey(UP_DOWN) ? res.getBoolean(UP_DOWN) : tru e);
77 mCenterView = (res.containsKey(CENTER) ? res.getBoolean(CENTER) : true);
78 mTooltipEdgeMargin =
79 context.getResources().getDimensionPixelSize(R.dimen.tooltip_min _edge_margin);
80 mTooltipTopMargin =
81 context.getResources().getDimensionPixelSize(R.dimen.tooltip_top _margin);
82 mBubbleTipXMargin = context.getResources().getDimensionPixelSize(R.dimen .bubble_tip_margin);
83
84 setBackgroundDrawable(new BubbleBackgroundDrawable(context, res));
85 setAnimationStyle(res.containsKey(ANIM_STYLE_ID) ? res.getInt(ANIM_STYLE _ID)
86 : android.R.style.Anima tion);
87
88 mTooltipText = new TextView(context);
89 mTooltipText.setTextAppearance(context,
90 (res.containsKey(TEXT_STYLE_ID) ? res.getInt(TEXT_STYLE_ID) : R. style.info_bubble));
91
92 setContentView(mTooltipText);
93 setWindowLayoutMode(
94 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP _CONTENT);
95 }
96
97 /**
98 * @return The textview for the bubble text.
99 */
100 public TextView getBubbleTextView() {
101 return mTooltipText;
102 }
103
104 /**
105 * Shows a text bubble anchored to the given view.
106 *
107 * @param text The text to be shown.
108 * @param anchorView The view that the bubble should be anchored to.
109 * @param maxWidth The maximum width of the text bubble.
110 * @param maxHeight The maximum height of the text bubble.
111 */
112 public void showTextBubble(String text, View anchorView, int maxWidth, int m axHeight) {
113 mTooltipText.setText(text);
114 mTooltipText.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.A T_MOST),
115 MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST));
116 mAnchorView = anchorView;
117 calculateNewPosition();
118 showAtCalculatedPosition();
119 }
120
121 /**
122 * Calculates the new position for the bubble, updating mXPosition, mYPositi on, mYOffset and
123 * the bubble arrow offset information without updating the UI. To see the c hanges,
124 * showAtCalculatedPosition should be called explicitly.
125 */
126 private void calculateNewPosition() {
127 View offsetView = mAnchorView;
128 int xOffset = 0;
129 int yOffset = 0;
130 if (mAnchorBelow) yOffset = mAnchorView.getHeight();
131
132 while (offsetView != null) {
133 xOffset += offsetView.getLeft();
134 yOffset += offsetView.getTop();
135 if (!(offsetView.getParent() instanceof View)) break;
136 offsetView = (View) offsetView.getParent();
137 }
138
139 if (mCenterView) {
140 // Center the tooltip over the view (calculating the width of the to oltip text).
141 xOffset += mAnchorView.getWidth() / 2;
142 } else if (LocalizationUtils.isLayoutRtl()) {
143 xOffset += mAnchorView.getWidth();
144 }
145
146 int tooltipWidth = mTooltipText.getMeasuredWidth();
147 xOffset -= tooltipWidth / 2;
148
149 // Account for the padding of the bubble background to ensure it is cent ered properly.
150 getBackground().getPadding(mCachedPaddingRect);
151 tooltipWidth += mCachedPaddingRect.left + mCachedPaddingRect.right;
152 xOffset -= mCachedPaddingRect.left;
153
154 int defaultXOffset = xOffset;
155
156 View rootView = mAnchorView.getRootView();
157 // Make sure the tooltip does not get rendered off the screen.
158 if (xOffset + tooltipWidth > rootView.getWidth()) {
159 xOffset = rootView.getWidth() - tooltipWidth - mTooltipEdgeMargin;
160 } else if (xOffset < 0) {
161 xOffset = mTooltipEdgeMargin;
162 }
163
164 // Move the bubble arrow to be centered over the anchor view.
165 int newOffset = -(xOffset - defaultXOffset);
166 if (Math.abs(newOffset) > mTooltipText.getMeasuredWidth() / 2 - mBubbleT ipXMargin) {
167 newOffset = (mTooltipText.getMeasuredWidth() / 2 - mBubbleTipXMargin )
168 * (int) Math.signum(newOffset);
169 }
170 ((BubbleBackgroundDrawable) getBackground()).setBubbleArrowXOffset(newOf fset);
171
172 if (mAnchorBelow) {
173 mXPosition = xOffset;
174 mYPosition = yOffset - mTooltipTopMargin;
175 } else {
176 mXPosition = xOffset;
177 mYPosition = mAnchorView.getRootView().getHeight() - yOffset + mTool tipTopMargin;
178 }
179 }
180
181 /**
182 * Shows the TextBubble in the precalculated position. Should be called afte r mXPosition
183 * and MYPosition has been set.
184 */
185 private void showAtCalculatedPosition() {
186 if (mAnchorBelow) {
187 showAtLocation(
188 mAnchorView.getRootView(), Gravity.TOP | Gravity.START, mXPo sition, mYPosition);
189 } else {
190 showAtLocation(mAnchorView.getRootView(), Gravity.BOTTOM | Gravity.S TART, mXPosition,
191 mYPosition);
192 }
193 }
194
195 // The two functions below are used for the floating animation.
196
197 /**
198 * Updates the y offset of the popup bubble (applied in addition to
199 * the default calculated offset).
200 * @param yoffset The new mYOffset to be used.
201 */
202 public void setOffsetY(int yoffset) {
203 update(mXPosition, mYPosition + yoffset, -1, -1);
204 }
205
206 /**
207 * Updates the position information and checks whether any positional change will occur. This
208 * method doesn't change the {@link TextBubble} if it is showing.
209 * @return Whether the TextBubble needs to be redrawn.
210 */
211 private boolean updatePosition() {
212 int previousX = mXPosition;
213 int previousY = mYPosition;
214 int previousOffset = ((BubbleBackgroundDrawable) getBackground()).getBub bleArrowOffset();
215 calculateNewPosition();
216 if (previousX != mXPosition || previousY != mYPosition
217 || previousOffset
218 != ((BubbleBackgroundDrawable) getBackground()).getBubbl eArrowOffset()) {
219 return true;
220 }
221 return false;
222 }
223
224 @Override
225 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
226 int oldTop, int oldRight, int oldBottom) {
227 boolean willDisappear = !mAnchorView.isShown();
228 boolean changePosition = updatePosition();
229 if (willDisappear) {
230 dismiss();
231 } else if (changePosition) {
232 dismiss();
233 showAtCalculatedPosition();
234 }
235 }
236
237 @Override
238 public void onViewAttachedToWindow(View v) {}
239
240 @Override
241 public void onViewDetachedFromWindow(View v) {
242 dismiss();
243 }
244
245 /**
246 * Drawable for rendering the background for a popup bubble.
247 *
248 * <p>Using a custom class as the LayerDrawable handles padding oddly and di d not allow the
249 * bubble arrow to be rendered below the content portion of the bubble if you specified
250 * padding, which is required to make it look nice.
251 */
252 static class BubbleBackgroundDrawable extends Drawable {
253 private final int mTooltipBorderWidth;
254 private final Rect mTooltipContentPadding;
255
256 private final Drawable mBubbleContentsDrawable;
257 private final BitmapDrawable mBubbleArrowDrawable;
258 private boolean mUp = false;
259 private int mBubbleArrowXOffset;
260
261 BubbleBackgroundDrawable(Context context, Bundle res) {
262 mUp = (res.containsKey(UP_DOWN) ? res.getBoolean(UP_DOWN) : true);
263 mBubbleContentsDrawable = context.getResources().getDrawable(R.drawa ble.bubble_white);
264 mBubbleArrowDrawable = (BitmapDrawable) context.getResources().getDr awable(
265 R.drawable.bubble_point_white);
266 mTooltipBorderWidth =
267 context.getResources().getDimensionPixelSize(R.dimen.tooltip _border_width);
268
269 if (res.getBoolean(BACKGROUND_INTRINSIC_PADDING, false)) {
270 mTooltipContentPadding = new Rect();
271 mBubbleContentsDrawable.getPadding(mTooltipContentPadding);
272 } else {
273 int padding = context.getResources().getDimensionPixelSize(
274 R.dimen.tooltip_content_padding);
275 mTooltipContentPadding = new Rect(padding, padding, padding, pad ding);
276 }
277 }
278
279 @Override
280 public void draw(Canvas canvas) {
281 mBubbleContentsDrawable.draw(canvas);
282 mBubbleArrowDrawable.draw(canvas);
283 }
284
285 @Override
286 protected void onBoundsChange(Rect bounds) {
287 if (bounds == null) return;
288
289 super.onBoundsChange(bounds);
290 int halfArrowWidth = mBubbleArrowDrawable.getIntrinsicWidth() / 2;
291 int halfBoundsWidth = bounds.width() / 2;
292 if (mUp) {
293 int contentsTop = bounds.top + mBubbleArrowDrawable.getIntrinsic Height()
294 - mTooltipBorderWidth;
295 mBubbleContentsDrawable.setBounds(
296 bounds.left, contentsTop, bounds.right, bounds.bottom);
297 mBubbleArrowDrawable.setBounds(
298 mBubbleArrowXOffset + halfBoundsWidth - halfArrowWidth, bounds.top,
299 mBubbleArrowXOffset + halfBoundsWidth + halfArrowWidth,
300 bounds.top + mBubbleArrowDrawable.getIntrinsicHeight());
301 } else {
302 int contentsBottom = bounds.bottom - mBubbleArrowDrawable.getInt rinsicHeight();
303 mBubbleContentsDrawable.setBounds(
304 bounds.left, bounds.left, bounds.right, contentsBottom);
305 mBubbleArrowDrawable.setBounds(
306 mBubbleArrowXOffset + halfBoundsWidth - halfArrowWidth,
307 contentsBottom - mTooltipBorderWidth,
308 mBubbleArrowXOffset + halfBoundsWidth + halfArrowWidth, contentsBottom
309 + mBubbleArrowDrawable.getIntrinsicHeight() - mT ooltipBorderWidth);
310 }
311 }
312
313 @Override
314 public void setAlpha(int alpha) {
315 mBubbleContentsDrawable.setAlpha(alpha);
316 mBubbleArrowDrawable.setAlpha(alpha);
317 }
318
319 @Override
320 public void setColorFilter(ColorFilter cf) {
321 // Not supported.
322 }
323
324 @Override
325 public int getOpacity() {
326 return PixelFormat.TRANSLUCENT;
327 }
328
329 @Override
330 public boolean getPadding(Rect padding) {
331 padding.set(mTooltipContentPadding);
332 if (mUp) {
333 padding.set(padding.left, padding.top + mBubbleArrowDrawable.get IntrinsicHeight(),
334 padding.right, padding.bottom);
335 } else {
336 padding.set(padding.left, padding.top, padding.right,
337 padding.bottom + mBubbleArrowDrawable.getIntrinsicHeight ());
338 }
339
340 return true;
341 }
342
343 /**
344 * Updates the additional X Offset for the bubble arrow. The arrow defa ults to being
345 * centered in the bubble, so this is delta from the center.
346 *
347 * @param xOffset The offset of the bubble arrow.
348 */
349 public void setBubbleArrowXOffset(int xOffset) {
350 mBubbleArrowXOffset = xOffset;
351 onBoundsChange(getBounds());
352 }
353
354 /**
355 * @return the current x offset for the bubble arrow.
356 */
357 public int getBubbleArrowOffset() {
358 return mBubbleArrowXOffset;
359 }
360 }
361 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698