OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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.omnibox; |
| 6 |
| 7 import android.animation.Animator; |
| 8 import android.animation.AnimatorListenerAdapter; |
| 9 import android.animation.AnimatorSet; |
| 10 import android.animation.ObjectAnimator; |
| 11 import android.annotation.SuppressLint; |
| 12 import android.content.Context; |
| 13 import android.os.SystemClock; |
| 14 import android.text.Layout; |
| 15 import android.text.TextUtils; |
| 16 import android.util.AttributeSet; |
| 17 import android.util.LayoutDirection; |
| 18 import android.view.View; |
| 19 import android.view.ViewGroup; |
| 20 import android.widget.TextView; |
| 21 |
| 22 import com.google.android.apps.chrome.R; |
| 23 |
| 24 import org.chromium.base.ApiCompatibilityUtils; |
| 25 import org.chromium.chrome.browser.util.MathUtils; |
| 26 import org.chromium.ui.interpolators.BakedBezierInterpolator; |
| 27 |
| 28 /** |
| 29 * Widget that handles displaying the URL. Adds the capability to show the trai
ling portion |
| 30 * of the URL in a separate text widget for animations. |
| 31 */ |
| 32 public class UrlContainer extends ViewGroup { |
| 33 private static final int MIN_TRAILING_TEXT_SHOW_DURATION_MS = 3000; |
| 34 private static final int MAX_TRAILING_TEXT_SHOW_DURATION_MS = 6000; |
| 35 private static final int TRAILING_TEXT_ANIMATION_DURATION_MS = 200; |
| 36 private static final float TRAILING_TEXT_TRANSLATION_X = 50f; |
| 37 |
| 38 private final Runnable mTriggerHideRunnable; |
| 39 private final Runnable mTriggerHideAnimationRunnable; |
| 40 |
| 41 private UrlBar mUrlBarView; |
| 42 private TextView mTrailingTextView; |
| 43 |
| 44 private int mUrlBarTextWidth; |
| 45 private boolean mShowTrailingText; |
| 46 private Animator mTrailingTextAnimator; |
| 47 private long mLastShowRequestTime; |
| 48 private boolean mUseDarkColors; |
| 49 |
| 50 /** |
| 51 * Constructor used to inflate from XML. |
| 52 */ |
| 53 public UrlContainer(Context context, AttributeSet attrs) { |
| 54 super(context, attrs); |
| 55 |
| 56 mTriggerHideRunnable = new Runnable() { |
| 57 @Override |
| 58 public void run() { |
| 59 setTrailingTextVisible(false); |
| 60 } |
| 61 }; |
| 62 mTriggerHideAnimationRunnable = new Runnable() { |
| 63 @Override |
| 64 public void run() { |
| 65 hideTrailingText(); |
| 66 } |
| 67 }; |
| 68 |
| 69 mUseDarkColors = true; |
| 70 } |
| 71 |
| 72 @Override |
| 73 protected void onFinishInflate() { |
| 74 super.onFinishInflate(); |
| 75 |
| 76 mUrlBarView = (UrlBar) findViewById(R.id.url_bar); |
| 77 assert mUrlBarView != null : "url_bar is not defined as a child."; |
| 78 |
| 79 mTrailingTextView = (TextView) findViewById(R.id.trailing_text); |
| 80 assert mTrailingTextView != null : "trailing_text is not defined as a ch
ild."; |
| 81 |
| 82 setClickable(true); |
| 83 } |
| 84 |
| 85 @Override |
| 86 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| 87 super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
| 88 |
| 89 int specWidth = MeasureSpec.getSize(widthMeasureSpec); |
| 90 mUrlBarView.measure( |
| 91 MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.EXACTLY), hei
ghtMeasureSpec); |
| 92 |
| 93 if (TextUtils.isEmpty(mUrlBarView.getText())) { |
| 94 mUrlBarTextWidth = specWidth; |
| 95 } else if (mUrlBarView.hasFocus()) { |
| 96 mUrlBarTextWidth = specWidth; |
| 97 } else { |
| 98 mUrlBarTextWidth = (int) Math.ceil(Math.min(specWidth, |
| 99 Layout.getDesiredWidth(mUrlBarView.getText(), mUrlBarView.ge
tPaint()))); |
| 100 } |
| 101 mTrailingTextView.measure( |
| 102 MeasureSpec.makeMeasureSpec(specWidth - mUrlBarTextWidth, Measur
eSpec.EXACTLY), |
| 103 heightMeasureSpec); |
| 104 } |
| 105 |
| 106 @SuppressLint("NewApi") |
| 107 @Override |
| 108 public void onRtlPropertiesChanged(int layoutDirection) { |
| 109 super.onRtlPropertiesChanged(layoutDirection); |
| 110 |
| 111 // Layout direction is driven by the text direction of the URL bar, so w
e just force |
| 112 // the path text view to match. |
| 113 switch (layoutDirection) { |
| 114 case LayoutDirection.LTR: |
| 115 ApiCompatibilityUtils.setTextDirection(mTrailingTextView, TEXT_D
IRECTION_LTR); |
| 116 break; |
| 117 case LayoutDirection.RTL: |
| 118 ApiCompatibilityUtils.setTextDirection(mTrailingTextView, TEXT_D
IRECTION_RTL); |
| 119 break; |
| 120 case LayoutDirection.LOCALE: |
| 121 ApiCompatibilityUtils.setTextDirection(mTrailingTextView, TEXT_D
IRECTION_LOCALE); |
| 122 break; |
| 123 case LayoutDirection.INHERIT: |
| 124 default: |
| 125 ApiCompatibilityUtils.setTextDirection(mTrailingTextView, TEXT_D
IRECTION_INHERIT); |
| 126 break; |
| 127 } |
| 128 } |
| 129 |
| 130 @Override |
| 131 protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| 132 int height = b - t; |
| 133 layoutChild(mUrlBarView, height, 0); |
| 134 if (ApiCompatibilityUtils.isLayoutRtl(mUrlBarView)) { |
| 135 layoutChild(mTrailingTextView, height, 0); |
| 136 } else { |
| 137 layoutChild(mTrailingTextView, height, mUrlBarTextWidth); |
| 138 } |
| 139 } |
| 140 |
| 141 private static void layoutChild(View view, int parentHeight, int childLeft)
{ |
| 142 int childTop = (parentHeight - view.getMeasuredHeight()) / 2; |
| 143 view.layout( |
| 144 childLeft, |
| 145 childTop, |
| 146 childLeft + view.getMeasuredWidth(), |
| 147 childTop + view.getMeasuredHeight()); |
| 148 } |
| 149 |
| 150 /** |
| 151 * Sets the text to be displayed. |
| 152 * |
| 153 * @param displayText The primary display text to be shown. |
| 154 * @param trailingText The additional trailing text to be shown after the di
splay text. |
| 155 * @param originalText The text that will be displayed if no display text is
specified, and |
| 156 * is also supplied to features such as cut and copy. |
| 157 * @return Whether any components of the URL have changed. |
| 158 */ |
| 159 public boolean setUrlText(String displayText, String trailingText, String or
iginalText) { |
| 160 boolean changed = mUrlBarView.setUrl(originalText, displayText); |
| 161 if (changed && mTrailingTextView.getVisibility() == VISIBLE) requestLayo
ut(); |
| 162 |
| 163 if (trailingText == null) trailingText = ""; |
| 164 if (!trailingText.equals(mTrailingTextView.getText())) { |
| 165 mTrailingTextView.setText(trailingText); |
| 166 changed |= true; |
| 167 } |
| 168 return changed; |
| 169 } |
| 170 |
| 171 /** |
| 172 * Specifies whether the trailing URL text should use dark text colors or li
ght colors. |
| 173 * @param useDarkColors Whether the text colors should be dark (i.e. appropr
iate for use |
| 174 * on a light background). |
| 175 */ |
| 176 public void setUseDarkTextColors(boolean useDarkColors) { |
| 177 mUseDarkColors = useDarkColors; |
| 178 mUrlBarView.setUseDarkTextColors(mUseDarkColors); |
| 179 |
| 180 int trailingTextColorId = R.color.url_emphasis_non_emphasized_text; |
| 181 if (!mUseDarkColors) { |
| 182 trailingTextColorId = R.color.url_emphasis_light_non_emphasized_text
; |
| 183 } |
| 184 mTrailingTextView.setTextColor(getResources().getColor(trailingTextColor
Id)); |
| 185 } |
| 186 |
| 187 /** |
| 188 * Updates the visibility of the trailing text view. |
| 189 * @param visible Whether the trailing text view should be visible. |
| 190 */ |
| 191 public void setTrailingTextVisible(boolean visible) { |
| 192 if (visible) mLastShowRequestTime = SystemClock.uptimeMillis(); |
| 193 |
| 194 if (visible == mShowTrailingText) return; |
| 195 mShowTrailingText = visible; |
| 196 |
| 197 removeCallbacks(mTriggerHideRunnable); |
| 198 removeCallbacks(mTriggerHideAnimationRunnable); |
| 199 |
| 200 if (visible) { |
| 201 if (mTrailingTextAnimator != null && mTrailingTextAnimator.isRunning
()) { |
| 202 mTrailingTextAnimator.cancel(); |
| 203 } else { |
| 204 float translationX = MathUtils.flipSignIf( |
| 205 TRAILING_TEXT_TRANSLATION_X, ApiCompatibilityUtils.isLay
outRtl(this)); |
| 206 mTrailingTextView.setAlpha(0f); |
| 207 mTrailingTextView.setTranslationX(translationX); |
| 208 } |
| 209 // Canceling the other animation will set the visibility to GONE, so
only update |
| 210 // this to VISIBLE after the above call to cancel(). |
| 211 mTrailingTextView.setVisibility(VISIBLE); |
| 212 |
| 213 if (!TextUtils.isEmpty(mTrailingTextView.getText())) { |
| 214 mUrlBarView.setAccessibilityTextOverride( |
| 215 TextUtils.concat(mUrlBarView.getText(), mTrailingTextVie
w.getText()) |
| 216 .toString()); |
| 217 } |
| 218 |
| 219 AnimatorSet set = new AnimatorSet(); |
| 220 set.playTogether( |
| 221 ObjectAnimator.ofFloat(mTrailingTextView, ALPHA, 1f), |
| 222 ObjectAnimator.ofFloat(mTrailingTextView, TRANSLATION_X, 0f)
); |
| 223 set.setDuration(TRAILING_TEXT_ANIMATION_DURATION_MS); |
| 224 set.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE); |
| 225 set.addListener(new AnimatorListenerAdapter() { |
| 226 @Override |
| 227 public void onAnimationEnd(Animator animation) { |
| 228 super.onAnimationEnd(animation); |
| 229 mTrailingTextAnimator = null; |
| 230 } |
| 231 }); |
| 232 set.start(); |
| 233 mTrailingTextAnimator = set; |
| 234 |
| 235 postDelayed(mTriggerHideRunnable, MAX_TRAILING_TEXT_SHOW_DURATION_MS
); |
| 236 } else { |
| 237 long elapsedTime = SystemClock.uptimeMillis() - mLastShowRequestTime
; |
| 238 if (elapsedTime >= MIN_TRAILING_TEXT_SHOW_DURATION_MS) { |
| 239 hideTrailingText(); |
| 240 } else { |
| 241 postDelayed(mTriggerHideAnimationRunnable, |
| 242 MIN_TRAILING_TEXT_SHOW_DURATION_MS - elapsedTime); |
| 243 } |
| 244 } |
| 245 } |
| 246 |
| 247 private void hideTrailingText() { |
| 248 if (mTrailingTextAnimator != null && mTrailingTextAnimator.isRunning())
{ |
| 249 mTrailingTextAnimator.cancel(); |
| 250 } |
| 251 |
| 252 mUrlBarView.setAccessibilityTextOverride(null); |
| 253 |
| 254 float translationX = MathUtils.flipSignIf( |
| 255 TRAILING_TEXT_TRANSLATION_X, ApiCompatibilityUtils.isLayoutRtl(t
his)); |
| 256 |
| 257 AnimatorSet set = new AnimatorSet(); |
| 258 set.playTogether( |
| 259 ObjectAnimator.ofFloat(mTrailingTextView, ALPHA, 0f), |
| 260 ObjectAnimator.ofFloat(mTrailingTextView, TRANSLATION_X, transla
tionX)); |
| 261 set.setDuration(TRAILING_TEXT_ANIMATION_DURATION_MS); |
| 262 set.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE); |
| 263 set.addListener(new AnimatorListenerAdapter() { |
| 264 @Override |
| 265 public void onAnimationEnd(Animator animation) { |
| 266 super.onAnimationEnd(animation); |
| 267 mTrailingTextView.setVisibility(GONE); |
| 268 mTrailingTextAnimator = null; |
| 269 } |
| 270 }); |
| 271 set.start(); |
| 272 mTrailingTextAnimator = set; |
| 273 } |
| 274 } |
OLD | NEW |