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

Side by Side Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months 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 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.toolbar;
6
7 import android.animation.Animator;
8 import android.animation.AnimatorListenerAdapter;
9 import android.animation.AnimatorSet;
10 import android.animation.ObjectAnimator;
11 import android.animation.ValueAnimator;
12 import android.animation.ValueAnimator.AnimatorUpdateListener;
13 import android.annotation.SuppressLint;
14 import android.content.Context;
15 import android.content.res.ColorStateList;
16 import android.content.res.Resources;
17 import android.graphics.Canvas;
18 import android.graphics.Color;
19 import android.graphics.Point;
20 import android.graphics.PorterDuff;
21 import android.graphics.Rect;
22 import android.graphics.drawable.BitmapDrawable;
23 import android.graphics.drawable.ColorDrawable;
24 import android.graphics.drawable.Drawable;
25 import android.graphics.drawable.TransitionDrawable;
26 import android.os.Build;
27 import android.os.SystemClock;
28 import android.util.AttributeSet;
29 import android.util.Property;
30 import android.view.Gravity;
31 import android.view.MotionEvent;
32 import android.view.View;
33 import android.view.View.OnClickListener;
34 import android.view.View.OnLongClickListener;
35 import android.view.ViewGroup;
36 import android.view.WindowManager;
37 import android.view.animation.LinearInterpolator;
38 import android.widget.FrameLayout;
39 import android.widget.ImageView;
40 import android.widget.TextView;
41 import android.widget.Toast;
42
43 import com.google.android.apps.chrome.R;
44
45 import org.chromium.base.ApiCompatibilityUtils;
46 import org.chromium.base.SysUtils;
47 import org.chromium.base.VisibleForTesting;
48 import org.chromium.base.metrics.RecordUserAction;
49 import org.chromium.chrome.browser.Tab;
50 import org.chromium.chrome.browser.compositor.Invalidator;
51 import org.chromium.chrome.browser.document.BrandColorUtils;
52 import org.chromium.chrome.browser.ntp.NewTabPage;
53 import org.chromium.chrome.browser.omnibox.LocationBar;
54 import org.chromium.chrome.browser.omnibox.LocationBarPhone;
55 import org.chromium.chrome.browser.omnibox.UrlContainer;
56 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
57 import org.chromium.chrome.browser.util.FeatureUtilities;
58 import org.chromium.chrome.browser.util.MathUtils;
59 import org.chromium.chrome.browser.widget.TintedImageButton;
60 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
61 import org.chromium.ui.base.LocalizationUtils;
62 import org.chromium.ui.interpolators.BakedBezierInterpolator;
63
64 import java.util.ArrayList;
65 import java.util.HashSet;
66 import java.util.List;
67 import java.util.Set;
68
69 /**
70 * Phone specific toolbar implementation.
71 */
72 public class ToolbarPhone extends ToolbarLayout
73 implements Invalidator.Client, OnClickListener, OnLongClickListener,
74 NewTabPage.OnSearchBoxScrollListener {
75
76 public static final int URL_FOCUS_CHANGE_ANIMATION_DURATION_MS = 250;
77 private static final int URL_FOCUS_TOOLBAR_BUTTONS_TRANSLATION_X_DP = 10;
78 private static final int URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS = 100;
79 private static final int URL_CLEAR_FOCUS_TABSTACK_DELAY_MS = 200;
80 private static final int URL_CLEAR_FOCUS_MENU_DELAY_MS = 250;
81
82 private static final int TAB_SWITCHER_MODE_ENTER_ANIMATION_DURATION_MS = 200 ;
83 private static final int TAB_SWITCHER_MODE_EXIT_NORMAL_ANIMATION_DURATION_MS = 200;
84 private static final int TAB_SWITCHER_MODE_EXIT_FADE_ANIMATION_DURATION_MS = 100;
85 private static final int TAB_SWITCHER_MODE_POST_EXIT_ANIMATION_DURATION_MS = 100;
86
87 private static final float UNINITIALIZED_PERCENT = -1f;
88
89 private static final int BRAND_COLOR_TRANSITION_DURATION_MS = 250;
90
91 static final int LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA = 51;
92
93 private LocationBarPhone mPhoneLocationBar;
94
95 private View mToolbarButtonsContainer;
96 private ImageView mToggleTabStackButton;
97 private NewTabButton mNewTabButton;
98 private TintedImageButton mHomeButton;
99 private TextView mUrlBar;
100 private UrlContainer mUrlContainer;
101 private View mUrlActionsContainer;
102 private ImageView mToolbarShadow;
103
104 private ObjectAnimator mTabSwitcherModeAnimation;
105 private ObjectAnimator mDelayedTabSwitcherModeAnimation;
106
107 private final List<View> mTabSwitcherModeViews = new ArrayList<View>();
108 private final Set<View> mBrowsingModeViews = new HashSet<View>();
109 private boolean mInTabSwitcherMode;
110 // This determines whether or not the toolbar draws as expected (false) or w hether it always
111 // draws as if it's showing the non-tabswitcher, non-animating toolbar. This is used in grabbing
112 // a bitmap to use as a texture representation of this view.
113 private boolean mTextureCaptureMode;
114 private boolean mAnimateNormalToolbar;
115 private boolean mDelayingTabSwitcherAnimation;
116
117 private ColorDrawable mTabSwitcherAnimationBgOverlay;
118 private TabSwitcherDrawable mTabSwitcherAnimationTabStackDrawable;
119 private Drawable mTabSwitcherAnimationMenuDrawable;
120 // Value that determines the amount of transition from the normal toolbar mo de to TabSwitcher
121 // mode. 0 = entirely in normal mode and 1.0 = entirely in TabSwitcher mode . In between values
122 // can be used for animating between the two view modes.
123 private float mTabSwitcherModePercent = 0;
124 private boolean mUIAnimatingTabSwitcherTransition;
125
126 // Used to clip the toolbar during the fade transition into and out of TabSw itcher mode. Only
127 // used when |mAnimateNormalToolbar| is false.
128 private Rect mClipRect;
129
130 private OnClickListener mTabSwitcherListener;
131 private OnClickListener mNewTabListener;
132
133 private boolean mUrlFocusChangeInProgress;
134 /** 1.0 is 100% focused, 0 is completely unfocused */
135 private float mUrlFocusChangePercent;
136 /** 1.0 is 100% expanded to full width, 0 is original collapsed size. */
137 private float mUrlExpansionPercent;
138 private AnimatorSet mUrlFocusLayoutAnimator;
139 private boolean mDisableLocationBarRelayout;
140 private boolean mLayoutLocationBarInFocusedMode;
141 private int mUnfocusedLocationBarLayoutWidth;
142 private int mUnfocusedLocationBarLayoutLeft;
143 private boolean mUnfocusedLocationBarUsesTransparentBg;
144
145 private int mUrlBackgroundAlpha = 255;
146 private float mNtpSearchBoxScrollPercent = UNINITIALIZED_PERCENT;
147 private ColorDrawable mToolbarBackground;
148 private Drawable mLocationBarBackground;
149 private boolean mForceDrawLocationBarBackground;
150 private TabSwitcherDrawable mTabSwitcherButtonDrawable;
151 private TabSwitcherDrawable mTabSwitcherButtonDrawableLight;
152
153 private final Rect mUrlViewportBounds = new Rect();
154 private final Rect mUrlBackgroundPadding = new Rect();
155 private final Rect mBackgroundOverlayBounds = new Rect();
156 private final Rect mLocationBarBackgroundOffset = new Rect();
157
158 private final Rect mNtpSearchBoxOriginalBounds = new Rect();
159 private final Rect mNtpSearchBoxTransformedBounds = new Rect();
160
161 private final int mLocationBarInsets;
162 private final int mToolbarSidePadding;
163
164 private ValueAnimator mBrandColorTransitionAnimation;
165 private boolean mBrandColorTransitionActive;
166
167 /**
168 * Used to specify the visual state of the toolbar.
169 */
170 private enum VisualState {
171 TAB_SWITCHER_INCOGNITO,
172 TAB_SWITCHER_NORMAL,
173 NORMAL,
174 INCOGNITO,
175 BRAND_COLOR,
176 NEW_TAB_NORMAL
177 }
178
179 private VisualState mVisualState = VisualState.NORMAL;
180 private VisualState mOverlayDrawablesVisualState;
181 private boolean mUseLightToolbarDrawables;
182
183 private NewTabPage mVisibleNewTabPage;
184 private float mPreTextureCaptureAlpha = 1f;
185 private boolean mIsOverlayTabStackDrawableLight;
186
187 // The following are some properties used during animation. We use explicit property classes
188 // to avoid the cost of reflection for each animation setup.
189
190 private final Property<ToolbarPhone, Float> mUrlFocusChangePercentProperty =
191 new Property<ToolbarPhone, Float>(Float.class, "") {
192 @Override
193 public Float get(ToolbarPhone object) {
194 return object.mUrlFocusChangePercent;
195 }
196
197 @Override
198 public void set(ToolbarPhone object, Float value) {
199 setUrlFocusChangePercent(value);
200 }
201 };
202
203 private final Property<ToolbarPhone, Float> mTabSwitcherModePercentProperty =
204 new Property<ToolbarPhone, Float>(Float.class, "") {
205 @Override
206 public Float get(ToolbarPhone object) {
207 return object.mTabSwitcherModePercent;
208 }
209
210 @Override
211 public void set(ToolbarPhone object, Float value) {
212 object.mTabSwitcherModePercent = value;
213 triggerPaintInvalidate(ToolbarPhone.this);
214 }
215 };
216
217 /**
218 * Constructs a ToolbarPhone object.
219 * @param context The Context in which this View object is created.
220 * @param attrs The AttributeSet that was specified with this View.
221 */
222 public ToolbarPhone(Context context, AttributeSet attrs) {
223 super(context, attrs);
224 mToolbarSidePadding = getResources().getDimensionPixelOffset(
225 R.dimen.toolbar_edge_padding);
226 // Insets used for the PhoneLocatioBar background drawable.
227 mLocationBarInsets = getResources().getDimensionPixelSize(R.dimen.locati on_bar_margin_top)
228 + getResources().getDimensionPixelSize(R.dimen.location_bar_marg in_bottom);
229 }
230
231 @Override
232 public void onFinishInflate() {
233 super.onFinishInflate();
234 Context context = getContext();
235
236 mPhoneLocationBar = (LocationBarPhone) findViewById(R.id.location_bar);
237
238 mToolbarButtonsContainer = findViewById(R.id.toolbar_buttons);
239
240 mToggleTabStackButton = (ImageView) findViewById(R.id.tab_switcher_butto n);
241 mToggleTabStackButton.setClickable(false);
242
243 Resources resources = getResources();
244 mTabSwitcherButtonDrawable =
245 TabSwitcherDrawable.createTabSwitcherDrawable(resources, false);
246 mTabSwitcherButtonDrawableLight =
247 TabSwitcherDrawable.createTabSwitcherDrawable(resources, true);
248
249 mToggleTabStackButton.setVisibility(FeatureUtilities.isDocumentMode(getC ontext())
250 ? GONE : VISIBLE);
251 mToggleTabStackButton.setImageDrawable(mTabSwitcherButtonDrawable);
252
253 mNewTabButton = (NewTabButton) findViewById(R.id.new_tab_button);
254 mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
255
256 mUrlBar = (TextView) findViewById(R.id.url_bar);
257 mUrlContainer = (UrlContainer) findViewById(R.id.url_container);
258
259 mUrlActionsContainer = findViewById(R.id.url_action_container);
260
261 mTabSwitcherModeViews.add(mNewTabButton);
262 mBrowsingModeViews.add(mPhoneLocationBar);
263
264 mToolbarBackground = new ColorDrawable(getToolbarColorForVisualState(Vis ualState.NORMAL));
265
266 mTabSwitcherAnimationBgOverlay =
267 new ColorDrawable(getToolbarColorForVisualState(VisualState.NORM AL));
268
269 mLocationBarBackground =
270 ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.ins et_textbox);
271 mLocationBarBackground.getPadding(mUrlBackgroundPadding);
272 mPhoneLocationBar.setPadding(
273 mUrlBackgroundPadding.left, mUrlBackgroundPadding.top,
274 mUrlBackgroundPadding.right, mUrlBackgroundPadding.bottom);
275
276 setLayoutTransition(null);
277
278 mMenuButton.setVisibility(shouldShowMenuButton() ? View.VISIBLE : View.G ONE);
279
280 // Ensure that the new tab button will not draw over the toolbar buttons if the translated
281 // string is long. Set a margin to the size of the toolbar button conta iner for the new
282 // tab button.
283 WindowManager wm = (WindowManager) context.getSystemService(Context.WIND OW_SERVICE);
284 Point screenSize = new Point();
285 wm.getDefaultDisplay().getSize(screenSize);
286
287 mToolbarButtonsContainer.measure(
288 MeasureSpec.makeMeasureSpec(screenSize.x, MeasureSpec.AT_MOST),
289 MeasureSpec.makeMeasureSpec(screenSize.y, MeasureSpec.AT_MOST));
290 ApiCompatibilityUtils.setMarginEnd(getFrameLayoutParams(mNewTabButton),
291 mToolbarButtonsContainer.getMeasuredWidth());
292
293 setWillNotDraw(false);
294 }
295
296 /**
297 * Sets up click and key listeners once we have native library available to handle clicks.
298 */
299 @Override
300 public void onNativeLibraryReady() {
301 super.onNativeLibraryReady();
302 getLocationBar().onNativeLibraryReady();
303 mToggleTabStackButton.setOnClickListener(this);
304 mToggleTabStackButton.setOnLongClickListener(this);
305 mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
306 @Override
307 public View getNextFocusForward() {
308 if (mMenuButton != null && mMenuButton.isShown()) {
309 return mMenuButton;
310 } else {
311 return getCurrentTabView();
312 }
313 }
314
315 @Override
316 public View getNextFocusBackward() {
317 return findViewById(R.id.url_bar);
318 }
319 });
320 mNewTabButton.setOnClickListener(this);
321 mHomeButton.setOnClickListener(this);
322
323 mMenuButton.setOnKeyListener(new KeyboardNavigationListener() {
324 @Override
325 public View getNextFocusForward() {
326 return getCurrentTabView();
327 }
328
329 @Override
330 public View getNextFocusBackward() {
331 return mToggleTabStackButton;
332 }
333
334 @Override
335 protected boolean handleEnterKeyPress() {
336 return getMenuButtonHelper().onEnterKeyPress(mMenuButton);
337 }
338 });
339 onHomeButtonUpdate(HomepageManager.isHomepageEnabled(getContext()));
340
341 updateVisualsForToolbarState(mInTabSwitcherMode);
342 }
343
344 @Override
345 public boolean onInterceptTouchEvent(MotionEvent ev) {
346 // If the NTP is partially scrolled, prevent all touch events to the chi ld views. This
347 // is to not allow a secondary touch event to trigger entering the tab s witcher, which
348 // can lead to really odd snapshots and transitions to the switcher.
349 if (mNtpSearchBoxScrollPercent != 0f
350 && mNtpSearchBoxScrollPercent != 1f
351 && mNtpSearchBoxScrollPercent != UNINITIALIZED_PERCENT) {
352 return true;
353 }
354 return super.onInterceptTouchEvent(ev);
355 }
356
357 @Override
358 public void onClick(View v) {
359 if (mToggleTabStackButton == v) {
360 // The button is clickable before the native library is loaded
361 // and the listener is setup.
362 if (mToggleTabStackButton != null && mToggleTabStackButton.isClickab le()
363 && mTabSwitcherListener != null) {
364 mTabSwitcherListener.onClick(mToggleTabStackButton);
365 RecordUserAction.record("MobileToolbarShowStackView");
366 }
367 } else if (mNewTabButton == v) {
368 v.setEnabled(false);
369
370 if (mNewTabListener != null) {
371 mNewTabListener.onClick(v);
372 RecordUserAction.record("MobileToolbarStackViewNewTab");
373 RecordUserAction.record("MobileNewTabOpened");
374 // TODO(kkimlabs): Record UMA action for homepage button.
375 }
376 } else if (mHomeButton == v) {
377 openHomepage();
378 }
379 }
380
381 @Override
382 public boolean onLongClick(View v) {
383 int stringResourceId = -1;
384 if (v == mToggleTabStackButton) {
385 stringResourceId = R.string.open_tabs;
386 }
387 if (stringResourceId != -1) {
388 Context ctx = getContext();
389 // Display the tooltip for the view being long clicked.
390 final int screenWidth = getResources().getDisplayMetrics().widthPixe ls;
391 final int[] screenPos = new int[2];
392 v.getLocationOnScreen(screenPos);
393 final int width = v.getWidth();
394
395 Toast toast = Toast.makeText(
396 ctx, getResources().getString(stringResourceId), Toast.LENGT H_SHORT);
397 toast.setGravity(
398 Gravity.TOP | Gravity.END,
399 screenWidth - screenPos[0] - width / 2,
400 getHeight());
401 toast.show();
402 return true;
403 }
404 return false;
405 }
406
407 @Override
408 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
409 if (!mDisableLocationBarRelayout) {
410 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
411
412 boolean changed = layoutLocationBar(MeasureSpec.getSize(widthMeasure Spec));
413 setUrlFocusChangePercent(mUrlFocusChangePercent);
414 if (!changed) return;
415 } else {
416 updateUnfocusedLocationBarLayoutParams();
417 }
418
419 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
420 }
421
422 private void updateUnfocusedLocationBarLayoutParams() {
423 boolean hasVisibleViewPriorToUrlBar = false;
424 for (int i = 0; i < mPhoneLocationBar.getChildCount(); i++) {
425 View child = mPhoneLocationBar.getChildAt(i);
426 if (child == mUrlContainer) break;
427 if (child.getVisibility() != GONE) {
428 hasVisibleViewPriorToUrlBar = true;
429 break;
430 }
431 }
432
433 int leftViewBounds = getViewBoundsLeftOfLocationBar();
434 if (!hasVisibleViewPriorToUrlBar) leftViewBounds += mToolbarSidePadding;
435 int rightViewBounds = getViewBoundsRightOfLocationBar();
436
437 if (!mPhoneLocationBar.hasVisibleViewsAfterUrlBarWhenUnfocused()) {
438 // Add spacing between the end of the URL and the edge of the omnibo x drawable.
439 // This only applies if there is no end aligned view that should be visible
440 // while the omnibox is unfocused.
441 if (ApiCompatibilityUtils.isLayoutRtl(mPhoneLocationBar)) {
442 leftViewBounds += mToolbarSidePadding;
443 } else {
444 rightViewBounds -= mToolbarSidePadding;
445 }
446 }
447
448 mUnfocusedLocationBarLayoutWidth = rightViewBounds - leftViewBounds;
449 mUnfocusedLocationBarLayoutLeft = leftViewBounds;
450 }
451
452 /**
453 * @return The background drawable for the fullscreen overlay.
454 */
455 @VisibleForTesting
456 ColorDrawable getOverlayDrawable() {
457 return mTabSwitcherAnimationBgOverlay;
458 }
459
460 /**
461 * @return The background drawable for the toolbar view.
462 */
463 @VisibleForTesting
464 ColorDrawable getBackgroundDrawable() {
465 return mToolbarBackground;
466 }
467
468 @SuppressLint("RtlHardcoded")
469 private boolean layoutLocationBar(int containerWidth) {
470 // Note that Toolbar's direction depends on system layout direction whil e
471 // LocationBar's direction depends on its text inside.
472 FrameLayout.LayoutParams locationBarLayoutParams =
473 getFrameLayoutParams(getLocationBar().getContainerView());
474
475 // Chrome prevents layout_gravity="left" from being defined in XML, but it simplifies
476 // the logic, so it is manually specified here.
477 locationBarLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
478
479 int width = 0;
480 int leftMargin = 0;
481
482 // Always update the unfocused layout params regardless of whether we ar e using
483 // those in this current layout pass as they are needed for animations.
484 updateUnfocusedLocationBarLayoutParams();
485
486 if (mLayoutLocationBarInFocusedMode || mVisualState == VisualState.NEW_T AB_NORMAL) {
487 int priorVisibleWidth = 0;
488 for (int i = 0; i < mPhoneLocationBar.getChildCount(); i++) {
489 View child = mPhoneLocationBar.getChildAt(i);
490 if (child == mPhoneLocationBar.getFirstViewVisibleWhenFocused()) break;
491 if (child.getVisibility() == GONE) continue;
492 priorVisibleWidth += child.getMeasuredWidth();
493 }
494
495 width = containerWidth - (2 * mToolbarSidePadding) + priorVisibleWid th;
496 if (ApiCompatibilityUtils.isLayoutRtl(mPhoneLocationBar)) {
497 leftMargin = mToolbarSidePadding;
498 } else {
499 leftMargin = -priorVisibleWidth + mToolbarSidePadding;
500 }
501 } else {
502 width = mUnfocusedLocationBarLayoutWidth;
503 leftMargin = mUnfocusedLocationBarLayoutLeft;
504 }
505
506 boolean changed = false;
507 changed |= (width != locationBarLayoutParams.width);
508 locationBarLayoutParams.width = width;
509
510 changed |= (leftMargin != locationBarLayoutParams.leftMargin);
511 locationBarLayoutParams.leftMargin = leftMargin;
512
513 return changed;
514 }
515
516 private int getViewBoundsLeftOfLocationBar() {
517 // Uses getMeasuredWidth()s instead of getLeft() because this is called in onMeasure
518 // and the layout values have not yet been set.
519 if (mVisualState == VisualState.NEW_TAB_NORMAL) {
520 return 0;
521 } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
522 return Math.max(
523 mToolbarSidePadding, mToolbarButtonsContainer.getMeasuredWid th());
524 } else {
525 return mHomeButton.getVisibility() != GONE
526 ? mHomeButton.getMeasuredWidth() : mToolbarSidePadding;
527 }
528 }
529
530 private int getViewBoundsRightOfLocationBar() {
531 // Uses getMeasuredWidth()s instead of getRight() because this is called in onMeasure
532 // and the layout values have not yet been set.
533 if (mVisualState == VisualState.NEW_TAB_NORMAL) {
534 return getMeasuredWidth();
535 } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
536 return getMeasuredWidth() - (mHomeButton.getVisibility() != GONE
537 ? mHomeButton.getMeasuredWidth() : mToolbarSidePadding);
538 } else {
539 int margin = Math.max(
540 mToolbarSidePadding, mToolbarButtonsContainer.getMeasuredWid th());
541 return getMeasuredWidth() - margin;
542 }
543 }
544
545 private void updateToolbarBackground(int color) {
546 mToolbarBackground.setColor(color);
547 invalidate();
548 }
549
550 private void updateToolbarBackground(VisualState visualState) {
551 updateToolbarBackground(getToolbarColorForVisualState(visualState));
552 }
553
554 private int getToolbarColorForVisualState(final VisualState visualState) {
555 Resources res = getResources();
556 switch (visualState) {
557 case NEW_TAB_NORMAL:
558 return Color.TRANSPARENT;
559 case NORMAL :
560 return res.getColor(R.color.default_primary_color);
561 case INCOGNITO:
562 return res.getColor(R.color.incognito_primary_color);
563 case BRAND_COLOR:
564 return getToolbarDataProvider().getPrimaryColor();
565 case TAB_SWITCHER_NORMAL:
566 case TAB_SWITCHER_INCOGNITO:
567 return res.getColor(R.color.tab_switcher_background);
568 default:
569 assert false;
570 return res.getColor(R.color.default_primary_color);
571 }
572 }
573
574 @Override
575 protected void dispatchDraw(Canvas canvas) {
576 if (!mTextureCaptureMode && mToolbarBackground.getColor() != Color.TRANS PARENT) {
577 // Update to compensate for orientation changes.
578 mToolbarBackground.setBounds(0, 0, getWidth(), getHeight());
579 mToolbarBackground.draw(canvas);
580 }
581
582 if (mLocationBarBackground != null
583 && (mPhoneLocationBar.getVisibility() == VISIBLE || mTextureCapt ureMode)) {
584 // Calculate the visible boundaries of the left and right most child views
585 // of the location bar.
586 int leftViewPosition = getViewBoundsLeftOfLocationBar();
587 int rightViewPosition = getViewBoundsRightOfLocationBar();
588
589 leftViewPosition -= mUrlBackgroundPadding.left;
590 if (mUrlExpansionPercent != 0f) {
591 leftViewPosition *= (1f - mUrlExpansionPercent);
592 leftViewPosition -= mUrlBackgroundPadding.left * mUrlExpansionPe rcent;
593 }
594
595 rightViewPosition += mUrlBackgroundPadding.right;
596 if (mUrlExpansionPercent != 0f) {
597 rightViewPosition += ((getWidth() - rightViewPosition) * mUrlExp ansionPercent);
598 rightViewPosition += mUrlBackgroundPadding.right * mUrlExpansion Percent;
599 }
600
601 // The bounds are set by the following:
602 // - The left most visible location bar child view.
603 // - The top of the viewport is aligned with the top of the location bar.
604 // - The right most visible location bar child view.
605 // - The bottom of the viewport is aligned with the bottom of the lo cation bar.
606 // Additional padding can be applied for use during animations.
607 mUrlViewportBounds.set(
608 leftViewPosition,
609 0,
610 rightViewPosition,
611 (int) (mPhoneLocationBar.getMeasuredHeight()
612 + (getHeight() - mPhoneLocationBar.getMeasuredHeight ()
613 + mUrlBackgroundPadding.bottom + mUrlBackgro undPadding.top)
614 * mUrlExpansionPercent));
615 mUrlViewportBounds.offset(0, (int) (mPhoneLocationBar.getY()
616 - (mUrlBackgroundPadding.top * mUrlExpansionPercent)));
617 }
618
619 if (mTextureCaptureMode) {
620 drawTabSwitcherAnimationOverlay(canvas, 0.f);
621 } else {
622 boolean tabSwitcherAnimationFinished = false;
623 if (mTabSwitcherModeAnimation != null) {
624 tabSwitcherAnimationFinished = !mTabSwitcherModeAnimation.isRunn ing();
625
626 // Perform the fade logic before super.dispatchDraw(canvas) so t hat we can properly
627 // set the values before the draw happens.
628 if (!mAnimateNormalToolbar) {
629 drawTabSwitcherFadeAnimation(
630 tabSwitcherAnimationFinished, mTabSwitcherModePercen t);
631 }
632 }
633
634 super.dispatchDraw(canvas);
635
636 if (mTabSwitcherModeAnimation != null) {
637 // Perform the overlay logic after super.dispatchDraw(canvas) as we need to draw on
638 // top of the current views.
639 if (mAnimateNormalToolbar) {
640 drawTabSwitcherAnimationOverlay(canvas, mTabSwitcherModePerc ent);
641 }
642
643 // Clear the animation.
644 if (tabSwitcherAnimationFinished) mTabSwitcherModeAnimation = nu ll;
645 }
646 }
647 }
648
649 // NewTabPage.OnSearchBoxScrollListener
650 @Override
651 public void onScrollChanged(float scrollPercentage) {
652 if (scrollPercentage == mNtpSearchBoxScrollPercent) return;
653
654 mNtpSearchBoxScrollPercent = scrollPercentage;
655 updateUrlExpansionPercent();
656 updateUrlExpansionAnimation();
657 }
658
659 /**
660 * Updates percentage of current the URL focus change animation.
661 * @param percent 1.0 is 100% focused, 0 is completely unfocused.
662 */
663 private void setUrlFocusChangePercent(float percent) {
664 mUrlFocusChangePercent = percent;
665 updateUrlExpansionPercent();
666 updateUrlExpansionAnimation();
667 }
668
669 private void updateUrlExpansionPercent() {
670 mUrlExpansionPercent = Math.max(mNtpSearchBoxScrollPercent, mUrlFocusCha ngePercent);
671 assert mUrlExpansionPercent >= 0;
672 assert mUrlExpansionPercent <= 1;
673 }
674
675 private void updateUrlExpansionAnimation() {
676 mLocationBarBackgroundOffset.setEmpty();
677
678 FrameLayout.LayoutParams locationBarLayoutParams =
679 getFrameLayoutParams(mPhoneLocationBar);
680 int currentLeftMargin = locationBarLayoutParams.leftMargin;
681 int currentWidth = locationBarLayoutParams.width;
682
683 float inversePercent = 1f - mUrlExpansionPercent;
684 boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mPhoneLocat ionBar);
685 if (ApiCompatibilityUtils.isLayoutRtl(mPhoneLocationBar)) {
686 mPhoneLocationBar.setTranslationX(
687 ((mUnfocusedLocationBarLayoutLeft + mUnfocusedLocationBarLay outWidth)
688 - (currentLeftMargin + currentWidth)) * inversePerce nt);
689 } else {
690 mPhoneLocationBar.setTranslationX(
691 (mUnfocusedLocationBarLayoutLeft - currentLeftMargin) * inve rsePercent);
692 mUrlActionsContainer.setTranslationX(-mPhoneLocationBar.getTranslati onX());
693 }
694
695 // Negate the location bar translation to keep the URL action container in the same
696 // place during the focus expansion. The check for RTL parity is requir ed because
697 // if they do not match then the action container will overlap the URL i f we do not
698 // allow it to be pushed off.
699 if (isLocationBarRtl == ApiCompatibilityUtils.isLayoutRtl(this)) {
700 mUrlActionsContainer.setTranslationX(-mPhoneLocationBar.getTranslati onX());
701 }
702
703 mPhoneLocationBar.setUrlFocusChangePercent(mUrlExpansionPercent);
704
705 // Ensure the buttons are invisible after focusing the omnibox to preven t them from
706 // accepting click events.
707 int toolbarButtonVisibility = mUrlExpansionPercent == 1f ? INVISIBLE : V ISIBLE;
708 mToolbarButtonsContainer.setVisibility(toolbarButtonVisibility);
709 if (mHomeButton.getVisibility() != GONE) {
710 mHomeButton.setVisibility(toolbarButtonVisibility);
711 }
712
713 // Force an invalidation of the location bar to properly handle the clip ping of the URL
714 // bar text as a result of the url action container translations.
715 mPhoneLocationBar.invalidate();
716 invalidate();
717
718 Tab currentTab = getToolbarDataProvider().getTab();
719 if (currentTab == null) return;
720
721 NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
722 // Explicitly use the focus change percentage here because it applies sc roll compensation
723 // that only applies during focus animations.
724 if (ntp != null) ntp.setUrlFocusChangeAnimationPercent(mUrlFocusChangePe rcent);
725
726 if (!isLocationBarShownInNTP()) {
727 // Reset these values in case we transitioned to a different page du ring the
728 // transition.
729 resetNtpAnimationValues();
730 return;
731 }
732
733 updateNtpTransitionAnimation(ntp);
734 }
735
736 private void resetNtpAnimationValues() {
737 mLocationBarBackgroundOffset.setEmpty();
738 mPhoneLocationBar.setTranslationY(0);
739 if (!mUrlFocusChangeInProgress) {
740 mToolbarButtonsContainer.setTranslationY(0);
741 mHomeButton.setTranslationY(0);
742 }
743 mToolbarShadow.setAlpha(1f);
744 mPhoneLocationBar.setAlpha(1);
745 mForceDrawLocationBarBackground = false;
746 mUrlBackgroundAlpha = isIncognito()
747 || (mUnfocusedLocationBarUsesTransparentBg
748 && !mUrlFocusChangeInProgress
749 && !mPhoneLocationBar.hasFocus())
750 ? LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA : 255;
751 setAncestorsShouldClipChildren(true);
752 mNtpSearchBoxScrollPercent = UNINITIALIZED_PERCENT;
753 }
754
755 private void updateNtpTransitionAnimation(NewTabPage ntp) {
756 if (mInTabSwitcherMode) return;
757
758 setAncestorsShouldClipChildren(mUrlExpansionPercent == 0f);
759 mToolbarShadow.setAlpha(0f);
760
761 float growthPercent = 0f;
762 if (mUrlExpansionPercent == 0f || mUrlExpansionPercent == 1f) {
763 growthPercent = 1f - mUrlExpansionPercent;
764 } else {
765 // During the transition from search box to omnibox, keep the omnibo x drawing
766 // at the same size of the search box for first 40% of the scroll tr ansition.
767 growthPercent = mUrlExpansionPercent <= 0.4f
768 ? 1f : Math.min(1f, (1f - mUrlExpansionPercent) * 1.66667f);
769 }
770
771 int paddingTop = mPhoneLocationBar.getPaddingTop();
772 int paddingBottom = mPhoneLocationBar.getPaddingBottom();
773
774 ntp.getSearchBoxBounds(mNtpSearchBoxOriginalBounds, mNtpSearchBoxTransfo rmedBounds);
775 float halfHeightDifference = (mNtpSearchBoxTransformedBounds.height()
776 - (mPhoneLocationBar.getMeasuredHeight() - paddingTop - paddingB ottom
777 + mLocationBarInsets)) / 2f;
778 mPhoneLocationBar.setTranslationY(growthPercent == 0f ? 0 : Math.max(0,
779 (mNtpSearchBoxTransformedBounds.top - mPhoneLocationBar.getTop()
780 + halfHeightDifference)));
781 if (!mUrlFocusChangeInProgress) {
782 float searchBoxTranslationY =
783 mNtpSearchBoxTransformedBounds.top - mNtpSearchBoxOriginalBo unds.top;
784 mToolbarButtonsContainer.setTranslationY(searchBoxTranslationY);
785 mHomeButton.setTranslationY(searchBoxTranslationY);
786 }
787
788 mLocationBarBackgroundOffset.set(
789 (int) ((mNtpSearchBoxTransformedBounds.left - mUrlViewportBounds .left
790 - mPhoneLocationBar.getPaddingLeft()) * growthPercent),
791 (int) ((-halfHeightDifference - paddingTop) * growthPercent),
792 (int) ((mNtpSearchBoxTransformedBounds.right - mUrlViewportBound s.right
793 + mPhoneLocationBar.getPaddingRight()) * growthPercent),
794 (int) ((halfHeightDifference - paddingBottom + mLocationBarInset s)
795 * growthPercent));
796
797 // The transparency of the location bar is dependent on how different it s size is
798 // from the final value. This is based on how much growth is applied be tween the
799 // desired size of the location bar to it's drawn size. The location ba r then only
800 // starts becoming opaque once the growth is at least half done.
801 if (growthPercent >= 0.5f) {
802 mPhoneLocationBar.setAlpha(0);
803 } else {
804 mPhoneLocationBar.setAlpha(1f - growthPercent * 2);
805 }
806
807 // Go from a transparent url background to a fully opaque one in the fir st 40% of the
808 // scroll transition.
809 mUrlBackgroundAlpha =
810 mUrlExpansionPercent >= 0.4f ? 255 : (int) ((mUrlExpansionPercen t * 2.5f) * 255);
811 if (mUrlExpansionPercent == 1f) mUrlBackgroundAlpha = 255;
812 mForceDrawLocationBarBackground = mUrlExpansionPercent != 0f;
813 }
814
815 private void setAncestorsShouldClipChildren(boolean clip) {
816 if (!isLocationBarShownInNTP()) return;
817 ViewGroup parent = this;
818 while (parent != null) {
819 parent.setClipChildren(clip);
820 if (!(parent.getParent() instanceof ViewGroup)) break;
821 if (parent.getId() == android.R.id.content) break;
822 parent = (ViewGroup) parent.getParent();
823 }
824 }
825
826 private void drawTabSwitcherFadeAnimation(boolean animationFinished, float p rogress) {
827 setAlpha(progress);
828 if (animationFinished) {
829 mClipRect = null;
830 } else if (mClipRect == null) {
831 mClipRect = new Rect();
832 }
833 if (mClipRect != null) mClipRect.set(0, 0, getWidth(), (int) (getHeight( ) * progress));
834 }
835
836 /**
837 * When entering and exiting the TabSwitcher mode, we fade out or fade in th e browsing
838 * mode of the toolbar on top of the TabSwitcher mode version of it. We do this by
839 * drawing all of the browsing mode views on top of the android view.
840 */
841 private void drawTabSwitcherAnimationOverlay(Canvas canvas, float animationP rogress) {
842 if (!isNativeLibraryReady()) return;
843
844 float floatAlpha = 1 - animationProgress;
845 int rgbAlpha = (int) (255 * floatAlpha);
846 canvas.save();
847 canvas.translate(0, -animationProgress * mBackgroundOverlayBounds.height ());
848 canvas.clipRect(mBackgroundOverlayBounds);
849
850 // Draw the background of the view we are leaving.
851 mTabSwitcherAnimationBgOverlay.setBounds(
852 0, 0, getMeasuredWidth(), getMeasuredHeight());
853 if (isLocationBarShownInNTP()) {
854 float ntpTransitionPercentage = mUrlExpansionPercent;
855 boolean shouldDrawWhite = ntpTransitionPercentage != 1.0f;
856 mTabSwitcherAnimationBgOverlay.setColor(shouldDrawWhite
857 ? Color.WHITE : getToolbarColorForVisualState(VisualState.NO RMAL));
858 }
859 mTabSwitcherAnimationBgOverlay.draw(canvas);
860
861 float previousAlpha = 0.f;
862 if (mHomeButton.getVisibility() != View.GONE) {
863 // Draw the New Tab button used in the URL view.
864 previousAlpha = mHomeButton.getAlpha();
865 mHomeButton.setAlpha(previousAlpha * floatAlpha);
866 drawChild(canvas, mHomeButton, SystemClock.uptimeMillis());
867 mHomeButton.setAlpha(previousAlpha);
868 }
869
870 // Draw the location/URL bar.
871 previousAlpha = mPhoneLocationBar.getAlpha();
872 mPhoneLocationBar.setAlpha(previousAlpha * floatAlpha);
873 // If the location bar is now fully transparent, do not bother drawing i t.
874 if (mPhoneLocationBar.getAlpha() != 0) {
875 drawChild(canvas, mPhoneLocationBar, SystemClock.uptimeMillis());
876 }
877 mPhoneLocationBar.setAlpha(previousAlpha);
878
879 // Draw the tab stack button and associated text.
880 translateCanvasToView(this, mToolbarButtonsContainer, canvas);
881
882 if (mTabSwitcherAnimationTabStackDrawable != null
883 && mToggleTabStackButton.getVisibility() != View.GONE) {
884 // Draw the tab stack button image.
885 canvas.save();
886 translateCanvasToView(mToolbarButtonsContainer, mToggleTabStackButto n, canvas);
887
888 int backgroundWidth = mToggleTabStackButton.getDrawable().getIntrins icWidth();
889 int backgroundHeight = mToggleTabStackButton.getDrawable().getIntrin sicHeight();
890 int backgroundLeft = (mToggleTabStackButton.getWidth()
891 - mToggleTabStackButton.getPaddingLeft()
892 - mToggleTabStackButton.getPaddingRight() - backgroundWidth) / 2;
893 backgroundLeft += mToggleTabStackButton.getPaddingLeft();
894 int backgroundTop = (mToggleTabStackButton.getHeight()
895 - mToggleTabStackButton.getPaddingTop()
896 - mToggleTabStackButton.getPaddingBottom() - backgroundHeigh t) / 2;
897 backgroundTop += mToggleTabStackButton.getPaddingTop();
898 canvas.translate(backgroundLeft, backgroundTop);
899
900 mTabSwitcherAnimationTabStackDrawable.setAlpha(rgbAlpha);
901 mTabSwitcherAnimationTabStackDrawable.draw(canvas);
902 canvas.restore();
903 }
904
905 // Draw the menu button if necessary.
906 if (mTabSwitcherAnimationMenuDrawable != null) {
907 mTabSwitcherAnimationMenuDrawable.setBounds(
908 mMenuButton.getPaddingLeft(), mMenuButton.getPaddingTop(),
909 mMenuButton.getWidth() - mMenuButton.getPaddingRight(),
910 mMenuButton.getHeight() - mMenuButton.getPaddingBottom());
911 translateCanvasToView(mToolbarButtonsContainer, mMenuButton, canvas) ;
912 mTabSwitcherAnimationMenuDrawable.setAlpha(rgbAlpha);
913 mTabSwitcherAnimationMenuDrawable.draw(canvas);
914 }
915
916 canvas.restore();
917 }
918
919 @Override
920 public void doInvalidate() {
921 postInvalidateOnAnimation();
922 }
923
924 /**
925 * Translates the canvas to ensure the specified view's coordinates are at 0 , 0.
926 *
927 * @param from The view the canvas is currently translated to.
928 * @param to The view to translate to.
929 * @param canvas The canvas to be translated.
930 *
931 * @throws IllegalArgumentException if {@code from} is not an ancestor of {@ code to}.
932 */
933 private static void translateCanvasToView(View from, View to, Canvas canvas)
934 throws IllegalArgumentException {
935 assert from != null;
936 assert to != null;
937 while (to != from) {
938 canvas.translate(to.getLeft(), to.getTop());
939 if (!(to.getParent() instanceof View)) {
940 throw new IllegalArgumentException("View 'to' was not a desenden t of 'from'.");
941 }
942 to = (View) to.getParent();
943 }
944 }
945
946 @Override
947 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
948 if (child == mPhoneLocationBar) return drawLocationBar(canvas, drawingTi me);
949 boolean clipped = false;
950
951 if (mLocationBarBackground != null
952 && ((!mInTabSwitcherMode && !mTabSwitcherModeViews.contains(chil d))
953 || (mInTabSwitcherMode && mBrowsingModeViews.contains(ch ild)))) {
954 canvas.save();
955 if (mUrlExpansionPercent != 0f && mUrlViewportBounds.top < child.get Bottom()) {
956 // For other child views, use the inverse clipping of the URL vi ewport.
957 // Only necessary during animations.
958 // Hardware mode does not support unioned clip regions, so clip using the
959 // appropriate bounds based on whether the child is to the left or right of the
960 // location bar.
961 boolean isLeft = (child == mNewTabButton || child == mHomeButton )
962 ^ LocalizationUtils.isLayoutRtl();
963
964 int clipTop = mUrlViewportBounds.top;
965 int clipBottom = mUrlViewportBounds.bottom;
966 boolean verticalClip = false;
967 if (mPhoneLocationBar.getTranslationY() > 0f) {
968 clipTop = child.getTop();
969 clipBottom = mUrlViewportBounds.top;
970 verticalClip = true;
971 }
972
973 if (isLeft) {
974 canvas.clipRect(
975 0, clipTop,
976 verticalClip ? child.getMeasuredWidth() : mUrlViewpo rtBounds.left,
977 clipBottom);
978 } else {
979 canvas.clipRect(
980 verticalClip ? 0 : mUrlViewportBounds.right,
981 clipTop, getMeasuredWidth(), clipBottom);
982 }
983 }
984 clipped = true;
985 }
986 boolean retVal = super.drawChild(canvas, child, drawingTime);
987 if (clipped) canvas.restore();
988 return retVal;
989 }
990
991 private boolean drawLocationBar(Canvas canvas, long drawingTime) {
992 boolean clipped = false;
993 float locationBarClipLeft = 0;
994 float locationBarClipRight = 0;
995 float locationBarClipTop = 0;
996 float locationBarClipBottom = 0;
997
998 if (mLocationBarBackground != null && (!mInTabSwitcherMode || mTextureCa ptureMode)) {
999 canvas.save();
1000 int backgroundAlpha = mUrlBackgroundAlpha;
1001 if (mTabSwitcherModeAnimation != null) {
1002 // Fade out/in the location bar towards the beginning of the ani mations to avoid
1003 // large jumps of stark white.
1004 backgroundAlpha =
1005 (int) (Math.pow(mPhoneLocationBar.getAlpha(), 3) * backg roundAlpha);
1006 } else if (getToolbarDataProvider().isUsingBrandColor()
1007 && !mBrandColorTransitionActive) {
1008 int unfocusedAlpha = mUnfocusedLocationBarUsesTransparentBg
1009 ? LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA : 255;
1010 backgroundAlpha =
1011 (int) (mUrlExpansionPercent * (255 - unfocusedAlpha) + u nfocusedAlpha);
1012 }
1013 mLocationBarBackground.setAlpha(backgroundAlpha);
1014
1015 if (mPhoneLocationBar.getAlpha() > 0 || mForceDrawLocationBarBackgro und) {
1016 mLocationBarBackground.setBounds(
1017 mUrlViewportBounds.left + mLocationBarBackgroundOffset.l eft,
1018 mUrlViewportBounds.top + mLocationBarBackgroundOffset.to p,
1019 mUrlViewportBounds.right + mLocationBarBackgroundOffset. right,
1020 mUrlViewportBounds.bottom + mLocationBarBackgroundOffset .bottom);
1021 mLocationBarBackground.draw(canvas);
1022 }
1023
1024 locationBarClipLeft = mUrlViewportBounds.left + mUrlBackgroundPaddin g.left
1025 + mLocationBarBackgroundOffset.left;
1026 locationBarClipRight = mUrlViewportBounds.right - mUrlBackgroundPadd ing.right
1027 + mLocationBarBackgroundOffset.right;
1028
1029 // When unexpanded, the location bar's visible content boundaries ar e inset from the
1030 // viewport used to draw the background. During expansion transitio ns, compensation
1031 // is applied to increase the clip regions such that when the locati on bar converts
1032 // to the narrower collapsed layout that the visible content is the same.
1033 if (mUrlExpansionPercent != 1f) {
1034 int leftDelta = mUnfocusedLocationBarLayoutLeft - getViewBoundsL eftOfLocationBar();
1035 int rightDelta = getViewBoundsRightOfLocationBar()
1036 - mUnfocusedLocationBarLayoutLeft
1037 - mUnfocusedLocationBarLayoutWidth;
1038 float inversePercent = 1f - mUrlExpansionPercent;
1039 locationBarClipLeft += leftDelta * inversePercent;
1040 locationBarClipRight -= rightDelta * inversePercent;
1041 }
1042
1043 locationBarClipTop = mUrlViewportBounds.top + mUrlBackgroundPadding. top
1044 + mLocationBarBackgroundOffset.top;
1045 locationBarClipBottom = mUrlViewportBounds.bottom - mUrlBackgroundPa dding.bottom
1046 + mLocationBarBackgroundOffset.bottom;
1047 // Clip the location bar child to the URL viewport calculated in onD raw.
1048 canvas.clipRect(
1049 locationBarClipLeft, locationBarClipTop,
1050 locationBarClipRight, locationBarClipBottom);
1051 clipped = true;
1052 }
1053
1054 boolean retVal = super.drawChild(canvas, mPhoneLocationBar, drawingTime) ;
1055
1056 if (clipped) canvas.restore();
1057 return retVal;
1058 }
1059
1060 @Override
1061 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1062 mBackgroundOverlayBounds.set(0, 0, w, mToolbarHeightWithoutShadow);
1063 if (mTabSwitcherAnimationBgOverlay != null) {
1064 mTabSwitcherAnimationBgOverlay.setBounds(0, 0, w, h);
1065 }
1066 super.onSizeChanged(w, h, oldw, oldh);
1067 }
1068
1069 @Override
1070 protected void onAttachedToWindow() {
1071 super.onAttachedToWindow();
1072 mToolbarShadow = (ImageView) getRootView().findViewById(R.id.toolbar_sha dow);
1073 }
1074
1075 @Override
1076 public void draw(Canvas canvas) {
1077 // If capturing a texture of the toolbar, ensure the alpha is set prior to draw(...) being
1078 // called. The alpha is being used prior to getting to draw(...), so up dating the value
1079 // after this point was having no affect.
1080 if (mTextureCaptureMode) assert getAlpha() == 1f;
1081 if (!mTextureCaptureMode && mClipRect != null) {
1082 canvas.save();
1083 canvas.clipRect(mClipRect);
1084 }
1085 super.draw(canvas);
1086 if (!mTextureCaptureMode && mClipRect != null) canvas.restore();
1087 }
1088
1089 @Override
1090 public void onStateRestored() {
1091 mToggleTabStackButton.setClickable(true);
1092 }
1093
1094 @Override
1095 public boolean isReadyForTextureCapture() {
1096 return !(mInTabSwitcherMode || mTabSwitcherModeAnimation != null
1097 || urlHasFocus() || mUrlFocusChangeInProgress);
1098 }
1099
1100 @Override
1101 protected void onNavigatedToDifferentPage() {
1102 super.onNavigatedToDifferentPage();
1103 if (FeatureUtilities.isDocumentMode(getContext())) {
1104 mUrlContainer.setTrailingTextVisible(true);
1105 }
1106 }
1107
1108 @Override
1109 public void setLoadProgress(int progress) {
1110 super.setLoadProgress(progress);
1111 if (FeatureUtilities.isDocumentMode(getContext()) && progress == 100) {
1112 mUrlContainer.setTrailingTextVisible(false);
1113 }
1114 }
1115
1116 @Override
1117 public void finishAnimations() {
1118 mClipRect = null;
1119 if (mTabSwitcherModeAnimation != null) {
1120 mTabSwitcherModeAnimation.end();
1121 mTabSwitcherModeAnimation = null;
1122 }
1123 if (mDelayedTabSwitcherModeAnimation != null) {
1124 mDelayedTabSwitcherModeAnimation.end();
1125 mDelayedTabSwitcherModeAnimation = null;
1126 }
1127 }
1128
1129 @Override
1130 public void getLocationBarContentRect(Rect outRect) {
1131 if (isLocationBarShownInNTP() && !isFocused()) {
1132 outRect.setEmpty();
1133 return;
1134 }
1135
1136 super.getLocationBarContentRect(outRect);
1137 }
1138
1139 @Override
1140 protected void onHomeButtonUpdate(boolean homeButtonEnabled) {
1141 if (homeButtonEnabled) {
1142 mHomeButton.setVisibility(urlHasFocus() || mInTabSwitcherMode ? INVI SIBLE : VISIBLE);
1143 if (!mBrowsingModeViews.contains(mHomeButton)) {
1144 mBrowsingModeViews.add(mHomeButton);
1145 }
1146 } else {
1147 mHomeButton.setVisibility(GONE);
1148 mBrowsingModeViews.remove(mHomeButton);
1149 }
1150 }
1151
1152 private ObjectAnimator createEnterTabSwitcherModeAnimation() {
1153 ObjectAnimator enterAnimation =
1154 ObjectAnimator.ofFloat(this, mTabSwitcherModePercentProperty, 1. f);
1155 enterAnimation.setDuration(TAB_SWITCHER_MODE_ENTER_ANIMATION_DURATION_MS );
1156 enterAnimation.setInterpolator(new LinearInterpolator());
1157 enterAnimation.addListener(new AnimatorListenerAdapter() {
1158 @Override
1159 public void onAnimationEnd(Animator animation) {
1160 // This is to deal with the view going invisible when resuming t he activity and
1161 // running this animation. The view is still there and clickabl e but does not
1162 // render and only a layout triggers a refresh. See crbug.com/3 06890.
1163 if (!mToggleTabStackButton.isEnabled()) requestLayout();
1164 }
1165 });
1166
1167 return enterAnimation;
1168 }
1169
1170 private ObjectAnimator createExitTabSwitcherAnimation(
1171 final boolean animateNormalToolbar) {
1172 ObjectAnimator exitAnimation =
1173 ObjectAnimator.ofFloat(this, mTabSwitcherModePercentProperty, 0. f);
1174 exitAnimation.setDuration(animateNormalToolbar
1175 ? TAB_SWITCHER_MODE_EXIT_NORMAL_ANIMATION_DURATION_MS
1176 : TAB_SWITCHER_MODE_EXIT_FADE_ANIMATION_DURATION_MS);
1177 exitAnimation.setInterpolator(new LinearInterpolator());
1178 exitAnimation.addListener(new AnimatorListenerAdapter() {
1179 @Override
1180 public void onAnimationEnd(Animator animation) {
1181 updateViewsForTabSwitcherMode(mInTabSwitcherMode);
1182 }
1183 });
1184
1185 return exitAnimation;
1186 }
1187
1188 private ObjectAnimator createPostExitTabSwitcherAnimation() {
1189 ObjectAnimator exitAnimation = ObjectAnimator.ofFloat(
1190 this, View.TRANSLATION_Y, -getHeight(), 0.f);
1191 exitAnimation.setDuration(TAB_SWITCHER_MODE_POST_EXIT_ANIMATION_DURATION _MS);
1192 exitAnimation.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1193 exitAnimation.addListener(new AnimatorListenerAdapter() {
1194 @Override
1195 public void onAnimationStart(Animator animation) {
1196 updateViewsForTabSwitcherMode(mInTabSwitcherMode);
1197 // On older builds, force an update to ensure the new visuals ar e used
1198 // when bringing in the toolbar. crbug.com/404571
1199 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) {
1200 requestLayout();
1201 }
1202 }
1203
1204 @Override
1205 public void onAnimationEnd(Animator animation) {
1206 mDelayedTabSwitcherModeAnimation = null;
1207 updateShadowVisibility(mInTabSwitcherMode);
1208 updateViewsForTabSwitcherMode(mInTabSwitcherMode);
1209 }
1210 });
1211
1212 return exitAnimation;
1213 }
1214
1215 @Override
1216 public void setTextureCaptureMode(boolean textureMode) {
1217 assert mTextureCaptureMode != textureMode;
1218 mTextureCaptureMode = textureMode;
1219 if (mTextureCaptureMode) {
1220 mPreTextureCaptureAlpha = getAlpha();
1221 setAlpha(1);
1222 } else {
1223 setAlpha(mPreTextureCaptureAlpha);
1224 mPreTextureCaptureAlpha = 1f;
1225 }
1226 }
1227
1228 private boolean isTabSwitcherAnimationRunning() {
1229 return mUIAnimatingTabSwitcherTransition
1230 || (mTabSwitcherModeAnimation != null && mTabSwitcherModeAnimati on.isRunning())
1231 || (mDelayedTabSwitcherModeAnimation != null
1232 && mDelayedTabSwitcherModeAnimation.isRunning()) ;
1233 }
1234
1235 private void updateViewsForTabSwitcherMode(boolean isInTabSwitcherMode) {
1236 int tabSwitcherViewsVisibility = isInTabSwitcherMode ? VISIBLE : INVISIB LE;
1237 int browsingViewsVisibility = isInTabSwitcherMode ? INVISIBLE : VISIBLE;
1238
1239 for (View view : mTabSwitcherModeViews) {
1240 view.setVisibility(tabSwitcherViewsVisibility);
1241 }
1242 for (View view : mBrowsingModeViews) {
1243 view.setVisibility(browsingViewsVisibility);
1244 }
1245 getProgressBar().setVisibility(
1246 isInTabSwitcherMode || isTabSwitcherAnimationRunning() ? INVISIB LE : VISIBLE);
1247 updateVisualsForToolbarState(isInTabSwitcherMode);
1248
1249 }
1250
1251 @Override
1252 protected void setContentAttached(boolean attached) {
1253 updateVisualsForToolbarState(mInTabSwitcherMode);
1254 }
1255
1256 @Override
1257 protected void setTabSwitcherMode(
1258 boolean inTabSwitcherMode, boolean showToolbar, boolean delayAnimati on) {
1259 if (mInTabSwitcherMode == inTabSwitcherMode) return;
1260
1261 finishAnimations();
1262
1263 mDelayingTabSwitcherAnimation = delayAnimation;
1264
1265 if (inTabSwitcherMode) {
1266 if (mUrlFocusLayoutAnimator != null && mUrlFocusLayoutAnimator.isRun ning()) {
1267 mUrlFocusLayoutAnimator.end();
1268 mUrlFocusLayoutAnimator = null;
1269 }
1270 mNewTabButton.setEnabled(true);
1271 updateViewsForTabSwitcherMode(true);
1272 mTabSwitcherModeAnimation = createEnterTabSwitcherModeAnimation();
1273 } else {
1274 if (!mDelayingTabSwitcherAnimation) {
1275 mTabSwitcherModeAnimation = createExitTabSwitcherAnimation(showT oolbar);
1276 }
1277 mUIAnimatingTabSwitcherTransition = true;
1278 }
1279
1280 mAnimateNormalToolbar = showToolbar;
1281 mInTabSwitcherMode = inTabSwitcherMode;
1282 if (mTabSwitcherModeAnimation != null) mTabSwitcherModeAnimation.start() ;
1283
1284 if (SysUtils.isLowEndDevice()) finishAnimations();
1285
1286 postInvalidateOnAnimation();
1287 }
1288
1289 @Override
1290 protected void onTabSwitcherTransitionFinished() {
1291 setAlpha(1.f);
1292 mClipRect = null;
1293 mUIAnimatingTabSwitcherTransition = false;
1294 if (!mAnimateNormalToolbar) {
1295 finishAnimations();
1296 updateVisualsForToolbarState(mInTabSwitcherMode);
1297 }
1298
1299 if (mDelayingTabSwitcherAnimation) {
1300 mDelayingTabSwitcherAnimation = false;
1301 mDelayedTabSwitcherModeAnimation = createPostExitTabSwitcherAnimatio n();
1302 mDelayedTabSwitcherModeAnimation.start();
1303 } else {
1304 updateViewsForTabSwitcherMode(mInTabSwitcherMode);
1305 }
1306 }
1307
1308 private void updateOverlayDrawables() {
1309 if (!isNativeLibraryReady()) return;
1310
1311 VisualState overlayState = computeVisualState(false);
1312 boolean visualStateChanged = mOverlayDrawablesVisualState != overlayStat e;
1313
1314 if (!visualStateChanged && mVisualState == VisualState.BRAND_COLOR
1315 && getToolbarDataProvider().getPrimaryColor()
1316 != mTabSwitcherAnimationBgOverlay.getColor()) {
1317 visualStateChanged = true;
1318 }
1319 if (!visualStateChanged) return;
1320
1321 mOverlayDrawablesVisualState = overlayState;
1322 mTabSwitcherAnimationBgOverlay.setColor(getToolbarColorForVisualState(
1323 mOverlayDrawablesVisualState));
1324
1325 if (shouldShowMenuButton()) {
1326 Resources res = getResources();
1327 mTabSwitcherAnimationMenuDrawable = ApiCompatibilityUtils.getDrawabl e(
1328 res, R.drawable.btn_menu).mutate();
1329 mTabSwitcherAnimationMenuDrawable.setColorFilter(isIncognito() ? Col or.WHITE
1330 : getResources().getColor(R.color.light_normal_color),
1331 PorterDuff.Mode.SRC_IN);
1332 ((BitmapDrawable) mTabSwitcherAnimationMenuDrawable).setGravity(Grav ity.CENTER);
1333 }
1334 }
1335
1336 @Override
1337 public void setOnTabSwitcherClickHandler(OnClickListener listener) {
1338 mTabSwitcherListener = listener;
1339 }
1340
1341 @Override
1342 public void setOnNewTabClickHandler(OnClickListener listener) {
1343 mNewTabListener = listener;
1344 }
1345
1346 @Override
1347 public boolean shouldIgnoreSwipeGesture() {
1348 return super.shouldIgnoreSwipeGesture() || mUrlExpansionPercent > 0f;
1349 }
1350
1351 private Property<TextView, Integer> buildUrlScrollProperty(
1352 final View containerView, final boolean isContainerRtl) {
1353 // If the RTL-ness of the container view changes during an animation, th e scroll values
1354 // become invalid. If that happens, snap to the ending position and no longer update.
1355 return new Property<TextView, Integer>(Integer.class, "scrollX") {
1356 private boolean mRtlStateInvalid;
1357
1358 @Override
1359 public Integer get(TextView view) {
1360 return view.getScrollX();
1361 }
1362
1363 @Override
1364 public void set(TextView view, Integer scrollX) {
1365 if (mRtlStateInvalid) return;
1366 boolean rtl = ApiCompatibilityUtils.isLayoutRtl(containerView);
1367 if (rtl != isContainerRtl) {
1368 mRtlStateInvalid = true;
1369 if (!rtl || mUrlBar.getLayout() != null) {
1370 scrollX = 0;
1371 if (rtl) {
1372 scrollX = (int) view.getLayout().getPrimaryHorizonta l(0);
1373 scrollX -= view.getWidth();
1374 }
1375 }
1376 }
1377 view.setScrollX(scrollX);
1378 }
1379 };
1380 }
1381
1382 private void populateUrlFocusingAnimatorSet(List<Animator> animators) {
1383 Animator animator = ObjectAnimator.ofFloat(this, mUrlFocusChangePercentP roperty, 1f);
1384 animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
1385 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1386 animators.add(animator);
1387
1388 for (int i = 0; i < mPhoneLocationBar.getChildCount(); i++) {
1389 View childView = mPhoneLocationBar.getChildAt(i);
1390 if (childView == mPhoneLocationBar.getFirstViewVisibleWhenFocused()) break;
1391 animator = ObjectAnimator.ofFloat(childView, ALPHA, 0);
1392 animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
1393 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1394 animators.add(animator);
1395 }
1396
1397 float density = getContext().getResources().getDisplayMetrics().density;
1398 boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
1399 float toolbarButtonTranslationX = MathUtils.flipSignIf(
1400 URL_FOCUS_TOOLBAR_BUTTONS_TRANSLATION_X_DP, isRtl) * density;
1401
1402 animator = ObjectAnimator.ofFloat(
1403 mMenuButton, TRANSLATION_X, toolbarButtonTranslationX);
1404 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1405 animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
1406 animators.add(animator);
1407
1408 animator = ObjectAnimator.ofFloat(mMenuButton, ALPHA, 0);
1409 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1410 animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
1411 animators.add(animator);
1412
1413 if (mToggleTabStackButton.getVisibility() != GONE) {
1414 animator = ObjectAnimator.ofFloat(
1415 mToggleTabStackButton, TRANSLATION_X, toolbarButtonTranslati onX);
1416 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1417 animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
1418 animators.add(animator);
1419
1420 animator = ObjectAnimator.ofFloat(mToggleTabStackButton, ALPHA, 0);
1421 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1422 animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
1423 animators.add(animator);
1424 }
1425 }
1426
1427 private void populateUrlClearFocusingAnimatorSet(List<Animator> animators) {
1428 Animator animator = ObjectAnimator.ofFloat(this, mUrlFocusChangePercentP roperty, 0f);
1429 animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
1430 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1431 animators.add(animator);
1432
1433 animator = ObjectAnimator.ofFloat(mMenuButton, TRANSLATION_X, 0);
1434 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1435 animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
1436 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1437 animators.add(animator);
1438
1439 animator = ObjectAnimator.ofFloat(mMenuButton, ALPHA, 1);
1440 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1441 animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
1442 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1443 animators.add(animator);
1444
1445 if (mToggleTabStackButton.getVisibility() != GONE) {
1446 animator = ObjectAnimator.ofFloat(mToggleTabStackButton, TRANSLATION _X, 0);
1447 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1448 animator.setStartDelay(URL_CLEAR_FOCUS_TABSTACK_DELAY_MS);
1449 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1450 animators.add(animator);
1451
1452 animator = ObjectAnimator.ofFloat(mToggleTabStackButton, ALPHA, 1);
1453 animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1454 animator.setStartDelay(URL_CLEAR_FOCUS_TABSTACK_DELAY_MS);
1455 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1456 animators.add(animator);
1457 }
1458
1459 for (int i = 0; i < mPhoneLocationBar.getChildCount(); i++) {
1460 View childView = mPhoneLocationBar.getChildAt(i);
1461 if (childView == mPhoneLocationBar.getFirstViewVisibleWhenFocused()) break;
1462 animator = ObjectAnimator.ofFloat(childView, ALPHA, 1);
1463 animator.setStartDelay(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
1464 animator.setDuration(URL_CLEAR_FOCUS_MENU_DELAY_MS);
1465 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
1466 animators.add(animator);
1467 }
1468
1469 if (isLocationBarShownInNTP() && mNtpSearchBoxScrollPercent == 0f) retur n;
1470
1471 if (!FeatureUtilities.isDocumentMode(getContext())
1472 || mPhoneLocationBar.showingQueryInTheOmnibox()) {
1473 // The call to getLayout() can return null briefly during text chang es, but as it
1474 // is only needed for RTL calculations, we proceed if the location b ar is showing
1475 // LTR content.
1476 boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mPhoneL ocationBar);
1477 if (!isLocationBarRtl || mUrlBar.getLayout() != null) {
1478 int urlBarStartScrollX = 0;
1479 if (isLocationBarRtl) {
1480 urlBarStartScrollX = (int) mUrlBar.getLayout().getPrimaryHor izontal(0);
1481 urlBarStartScrollX -= mUrlBar.getWidth();
1482 }
1483
1484 // If the scroll position matches the current scroll position, d o not trigger
1485 // this animation as it will cause visible jumps when going from cleared text
1486 // back to page URLs (despite it continually calling setScrollX with the same
1487 // number).
1488 if (mUrlBar.getScrollX() != urlBarStartScrollX) {
1489 animator = ObjectAnimator.ofInt(
1490 mUrlBar,
1491 buildUrlScrollProperty(mPhoneLocationBar, isLocation BarRtl),
1492 urlBarStartScrollX);
1493 animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS) ;
1494 animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_C URVE);
1495 animators.add(animator);
1496 }
1497 }
1498 }
1499 }
1500
1501 @Override
1502 public void onUrlFocusChange(final boolean hasFocus) {
1503 super.onUrlFocusChange(hasFocus);
1504
1505 triggerUrlFocusAnimation(hasFocus);
1506
1507 TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow. getDrawable();
1508 if (hasFocus) {
1509 shadowDrawable.startTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION_M S);
1510 } else {
1511 shadowDrawable.reverseTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION _MS);
1512 }
1513 }
1514
1515 private void triggerUrlFocusAnimation(final boolean hasFocus) {
1516 if (mUrlFocusLayoutAnimator != null && mUrlFocusLayoutAnimator.isRunning ()) {
1517 mUrlFocusLayoutAnimator.cancel();
1518 mUrlFocusLayoutAnimator = null;
1519 }
1520
1521 List<Animator> animators = new ArrayList<Animator>();
1522 if (hasFocus) {
1523 populateUrlFocusingAnimatorSet(animators);
1524 } else {
1525 populateUrlClearFocusingAnimatorSet(animators);
1526 }
1527 mUrlFocusLayoutAnimator = new AnimatorSet();
1528 mUrlFocusLayoutAnimator.playTogether(animators);
1529
1530 mUrlFocusChangeInProgress = true;
1531 mUrlFocusLayoutAnimator.addListener(new AnimatorListenerAdapter() {
1532 private boolean mCanceled;
1533
1534 @Override
1535 public void onAnimationStart(Animator animation) {
1536 if (!hasFocus) {
1537 mDisableLocationBarRelayout = true;
1538 } else {
1539 mLayoutLocationBarInFocusedMode = true;
1540 requestLayout();
1541 }
1542 }
1543
1544 @Override
1545 public void onAnimationCancel(Animator animation) {
1546 mCanceled = true;
1547 }
1548
1549 @Override
1550 public void onAnimationEnd(Animator animation) {
1551 if (mCanceled) return;
1552
1553 if (!hasFocus) {
1554 mDisableLocationBarRelayout = false;
1555 mLayoutLocationBarInFocusedMode = false;
1556 requestLayout();
1557 }
1558 mPhoneLocationBar.finishUrlFocusChange(hasFocus);
1559 mUrlFocusChangeInProgress = false;
1560 }
1561 });
1562 mUrlFocusLayoutAnimator.start();
1563 }
1564
1565 @Override
1566 protected boolean shouldShowMenuButton() {
1567 return !mPhoneLocationBar.showMenuButtonInOmnibox() && super.shouldShowM enuButton();
1568 }
1569
1570 @Override
1571 protected void updateTabCountVisuals(int numberOfTabs) {
1572 if (mToggleTabStackButton == null) return;
1573 mHomeButton.setEnabled(true);
1574
1575 mToggleTabStackButton.setEnabled(numberOfTabs >= 1);
1576 mToggleTabStackButton.setContentDescription(
1577 getResources().getString(R.string.accessibility_toolbar_btn_tabs witcher_toggle,
1578 numberOfTabs));
1579 mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncogn ito());
1580 mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito() );
1581
1582 boolean useTabStackDrawableLight = isIncognito();
1583 if (mTabSwitcherAnimationTabStackDrawable == null
1584 || mIsOverlayTabStackDrawableLight != useTabStackDrawableLight) {
1585 mTabSwitcherAnimationTabStackDrawable =
1586 TabSwitcherDrawable.createTabSwitcherDrawable(
1587 getResources(), useTabStackDrawableLight);
1588 int[] stateSet = {android.R.attr.state_enabled};
1589 mTabSwitcherAnimationTabStackDrawable.setState(stateSet);
1590 mTabSwitcherAnimationTabStackDrawable.setBounds(
1591 mToggleTabStackButton.getDrawable().getBounds());
1592 mIsOverlayTabStackDrawableLight = useTabStackDrawableLight;
1593 }
1594
1595 if (mTabSwitcherAnimationTabStackDrawable != null) {
1596 mTabSwitcherAnimationTabStackDrawable.updateForTabCount(
1597 numberOfTabs, isIncognito());
1598 }
1599 }
1600
1601 @Override
1602 protected void onTabContentViewChanged() {
1603 super.onTabContentViewChanged();
1604 updateNtpAnimationState();
1605 updateVisualsForToolbarState(mInTabSwitcherMode);
1606 }
1607
1608 @Override
1609 protected void onTabOrModelChanged() {
1610 super.onTabOrModelChanged();
1611 updateNtpAnimationState();
1612 updateVisualsForToolbarState(mInTabSwitcherMode);
1613 }
1614
1615 @Override
1616 protected void onPrimaryColorChanged() {
1617 super.onPrimaryColorChanged();
1618 if (mBrandColorTransitionActive) mBrandColorTransitionAnimation.cancel() ;
1619 final int initialColor = mToolbarBackground.getColor();
1620 final int finalColor = getToolbarDataProvider().getPrimaryColor();
1621 if (initialColor == finalColor) return;
1622 boolean shouldUseOpaque = BrandColorUtils.shouldUseOpaqueTextboxBackgrou nd(finalColor);
1623 final int initialAlpha = mUrlBackgroundAlpha;
1624 final int finalAlpha =
1625 shouldUseOpaque ? 255 : LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPH A;
1626 final boolean shouldAnimateAlpha = initialAlpha != finalAlpha;
1627 mBrandColorTransitionAnimation = ValueAnimator.ofFloat(0, 1)
1628 .setDuration(BRAND_COLOR_TRANSITION_DURATION_MS);
1629 mBrandColorTransitionAnimation.setInterpolator(BakedBezierInterpolator.T RANSFORM_CURVE);
1630 mBrandColorTransitionAnimation.addUpdateListener(new AnimatorUpdateListe ner() {
1631 @Override
1632 public void onAnimationUpdate(ValueAnimator animation) {
1633 float fraction = animation.getAnimatedFraction();
1634 int red = (int) (Color.red(initialColor)
1635 + fraction * (Color.red(finalColor) - Color.red(initialC olor)));
1636 int green = (int) (Color.green(initialColor)
1637 + fraction * (Color.green(finalColor) - Color.green(init ialColor)));
1638 int blue = (int) (Color.blue(initialColor)
1639 + fraction * (Color.blue(finalColor) - Color.blue(initia lColor)));
1640 if (shouldAnimateAlpha) {
1641 mUrlBackgroundAlpha =
1642 (int) (initialAlpha + fraction * (finalAlpha - initi alAlpha));
1643 }
1644 updateToolbarBackground(Color.rgb(red, green, blue));
1645 }
1646 });
1647 mBrandColorTransitionAnimation.addListener(new AnimatorListenerAdapter() {
1648 @Override
1649 public void onAnimationEnd(Animator animation) {
1650 mBrandColorTransitionActive = false;
1651 updateVisualsForToolbarState(mInTabSwitcherMode);
1652 }
1653 });
1654 mBrandColorTransitionAnimation.start();
1655 mBrandColorTransitionActive = true;
1656 }
1657
1658 private void updateNtpAnimationState() {
1659 // Store previous NTP scroll before calling reset as that clears this va lue.
1660 boolean wasShowingNtp = mVisibleNewTabPage != null;
1661 float previousNtpScrollPercent = mNtpSearchBoxScrollPercent;
1662
1663 resetNtpAnimationValues();
1664 if (mVisibleNewTabPage != null) {
1665 mVisibleNewTabPage.setSearchBoxScrollListener(null);
1666 mVisibleNewTabPage = null;
1667 }
1668 mVisibleNewTabPage = getToolbarDataProvider().getNewTabPageForCurrentTab ();
1669 if (mVisibleNewTabPage != null && mVisibleNewTabPage.isLocationBarShownI nNTP()) {
1670 mVisibleNewTabPage.setSearchBoxScrollListener(this);
1671 requestLayout();
1672 } else if (wasShowingNtp) {
1673 // Convert the previous NTP scroll percentage to URL focus percentag e because that
1674 // will give a nicer transition animation from the expanded NTP omni box to the
1675 // collapsed normal omnibox on other non-NTP pages.
1676 if (previousNtpScrollPercent > 0f) {
1677 mUrlFocusChangePercent =
1678 Math.max(previousNtpScrollPercent, mUrlFocusChangePercen t);
1679 triggerUrlFocusAnimation(false);
1680 }
1681 requestLayout();
1682 }
1683 }
1684
1685 @Override
1686 protected void onDefaultSearchEngineChanged() {
1687 super.onDefaultSearchEngineChanged();
1688 // Post an update for the toolbar state, which will allow all other list eners
1689 // for the search engine change to update before we check on the state o f the
1690 // world for a UI update.
1691 // TODO(tedchoc): Move away from updating based on the search engine cha nge and instead
1692 // add the toolbar as a listener to the NewTabPage and ud pate only when
1693 // it notifies the listeners that it has changed it's sta te.
1694 post(new Runnable() {
1695 @Override
1696 public void run() {
1697 updateVisualsForToolbarState(mInTabSwitcherMode);
1698 updateNtpAnimationState();
1699 }
1700 });
1701 }
1702
1703 @Override
1704 protected void handleFindToolbarStateChange(boolean showing) {
1705 setVisibility(showing ? View.GONE : View.VISIBLE);
1706 TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow. getDrawable();
1707 if (showing) {
1708 shadowDrawable.startTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION_M S);
1709 } else {
1710 shadowDrawable.reverseTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION _MS);
1711 }
1712 }
1713
1714 private boolean isLocationBarShownInNTP() {
1715 NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
1716 return ntp != null && ntp.isLocationBarShownInNTP();
1717 }
1718
1719 private void updateShadowVisibility(boolean isInTabSwitcherMode) {
1720 boolean shouldDrawShadow = !isInTabSwitcherMode && !isTabSwitcherAnimati onRunning();
1721 int shadowVisibility = shouldDrawShadow ? View.VISIBLE : View.INVISIBLE;
1722
1723 if (mToolbarShadow.getVisibility() != shadowVisibility) {
1724 mToolbarShadow.setVisibility(shadowVisibility);
1725 }
1726 }
1727
1728 private VisualState computeVisualState(boolean isInTabSwitcherMode) {
1729 if (isInTabSwitcherMode && isIncognito()) return VisualState.TAB_SWITCHE R_INCOGNITO;
1730 if (isInTabSwitcherMode && !isIncognito()) return VisualState.TAB_SWITCH ER_NORMAL;
1731 if (isLocationBarShownInNTP()) return VisualState.NEW_TAB_NORMAL;
1732 if (isIncognito()) return VisualState.INCOGNITO;
1733 if (getToolbarDataProvider().isUsingBrandColor()) return VisualState.BRA ND_COLOR;
1734 return VisualState.NORMAL;
1735 }
1736
1737 private void updateVisualsForToolbarState(boolean isInTabSwitcherMode) {
1738 if (mBrandColorTransitionActive) return;
1739 final boolean isIncognito = isIncognito();
1740
1741 VisualState visualState = computeVisualState(isInTabSwitcherMode);
1742 boolean visualStateChanged = mVisualState != visualState;
1743
1744 int currentPrimaryColor = getToolbarDataProvider().getPrimaryColor();
1745 if (mVisualState == VisualState.BRAND_COLOR && !visualStateChanged) {
1746 boolean useLightToolbarDrawables =
1747 BrandColorUtils.shouldUseLightDrawablesForToolbar(currentPri maryColor);
1748 boolean unfocusedLocationBarUsesTransparentBg =
1749 !BrandColorUtils.shouldUseOpaqueTextboxBackground(currentPri maryColor);
1750 if (useLightToolbarDrawables != mUseLightToolbarDrawables
1751 || unfocusedLocationBarUsesTransparentBg
1752 != mUnfocusedLocationBarUsesTransparentBg) {
1753 visualStateChanged = true;
1754 } else {
1755 updateToolbarBackground(VisualState.BRAND_COLOR);
1756 }
1757 }
1758
1759 mVisualState = visualState;
1760
1761 updateOverlayDrawables();
1762 updateShadowVisibility(isInTabSwitcherMode);
1763 if (!visualStateChanged) {
1764 if (mVisualState == VisualState.NEW_TAB_NORMAL) {
1765 updateNtpTransitionAnimation(
1766 getToolbarDataProvider().getNewTabPageForCurrentTab());
1767 }
1768 return;
1769 }
1770
1771 mUseLightToolbarDrawables = false;
1772 mUnfocusedLocationBarUsesTransparentBg = false;
1773 mUrlBackgroundAlpha = 255;
1774 int progressBarResource = R.drawable.progress_bar;
1775 updateToolbarBackground(mVisualState);
1776 if (isInTabSwitcherMode) {
1777 mUseLightToolbarDrawables = true;
1778 mUrlBackgroundAlpha = LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA;
1779 progressBarResource = R.drawable.progress_bar_white;
1780 } else if (isIncognito()) {
1781 mUseLightToolbarDrawables = true;
1782 mUrlBackgroundAlpha = LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA;
1783 progressBarResource = R.drawable.progress_bar_white;
1784 } else if (mVisualState == VisualState.BRAND_COLOR) {
1785 mUseLightToolbarDrawables =
1786 BrandColorUtils.shouldUseLightDrawablesForToolbar(currentPri maryColor);
1787 mUnfocusedLocationBarUsesTransparentBg =
1788 !BrandColorUtils.shouldUseOpaqueTextboxBackground(currentPri maryColor);
1789 mUrlBackgroundAlpha = mUnfocusedLocationBarUsesTransparentBg
1790 ? LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA : 255;
1791 progressBarResource = mUseLightToolbarDrawables
1792 ? R.drawable.progress_bar_white : R.drawable.progress_bar;
1793 } else {
1794 mUseLightToolbarDrawables = false;
1795 mUrlBackgroundAlpha = 255;
1796 progressBarResource = R.drawable.progress_bar;
1797 }
1798
1799 getProgressBar().setProgressDrawable(
1800 ApiCompatibilityUtils.getDrawable(getResources(), progressBarRes ource));
1801
1802 mToggleTabStackButton.setImageDrawable(mUseLightToolbarDrawables
1803 ? mTabSwitcherButtonDrawableLight : mTabSwitcherButtonDrawable);
1804
1805
1806 ColorStateList dark = getResources().getColorStateList(R.color.dark_mode _tint);
1807 ColorStateList white = getResources().getColorStateList(R.color.light_mo de_tint);
1808 if (shouldShowMenuButton()) {
1809 mMenuButton.setTint(mUseLightToolbarDrawables ? white : dark);
1810 }
1811 if (mHomeButton.getVisibility() != GONE) {
1812 mHomeButton.setTint(mUseLightToolbarDrawables ? white : dark);
1813 }
1814
1815 mPhoneLocationBar.updateVisualsForState();
1816
1817 // We update the alpha before comparing the visual state as we need to c hange
1818 // it's value when entering and exiting TabSwitcher mode.
1819 if (isLocationBarShownInNTP() && !isInTabSwitcherMode) {
1820 updateNtpTransitionAnimation(
1821 getToolbarDataProvider().getNewTabPageForCurrentTab());
1822 }
1823
1824 if (isInTabSwitcherMode) mNewTabButton.setIsIncognito(isIncognito);
1825
1826 CharSequence newTabContentDescription = getResources().getText(
1827 isIncognito ? R.string.accessibility_toolbar_btn_new_incognito_t ab :
1828 R.string.accessibility_toolbar_btn_new_tab);
1829 if (!newTabContentDescription.equals(mNewTabButton.getContentDescription ())) {
1830 mNewTabButton.setContentDescription(newTabContentDescription);
1831 }
1832 }
1833
1834 @Override
1835 public LocationBar getLocationBar() {
1836 return mPhoneLocationBar;
1837 }
1838 }
1839
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698