OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.ntp; | 5 package org.chromium.chrome.browser.ntp; |
6 | 6 |
7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.res.Configuration; | 9 import android.content.res.Configuration; |
10 import android.content.res.Resources; | 10 import android.content.res.Resources; |
11 import android.graphics.Bitmap; | 11 import android.graphics.Bitmap; |
12 import android.graphics.BitmapFactory; | 12 import android.graphics.BitmapFactory; |
13 import android.graphics.Canvas; | 13 import android.graphics.Canvas; |
14 import android.graphics.Color; | 14 import android.graphics.Color; |
15 import android.graphics.Point; | |
16 import android.graphics.Rect; | 15 import android.graphics.Rect; |
17 import android.graphics.drawable.BitmapDrawable; | 16 import android.graphics.drawable.BitmapDrawable; |
18 import android.support.v4.graphics.drawable.RoundedBitmapDrawable; | 17 import android.support.v4.graphics.drawable.RoundedBitmapDrawable; |
19 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; | 18 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; |
20 import android.support.v7.widget.RecyclerView; | 19 import android.support.v7.widget.RecyclerView; |
21 import android.support.v7.widget.helper.ItemTouchHelper; | 20 import android.support.v7.widget.helper.ItemTouchHelper; |
22 import android.text.Editable; | 21 import android.text.Editable; |
23 import android.text.TextUtils; | 22 import android.text.TextUtils; |
24 import android.text.TextWatcher; | 23 import android.text.TextWatcher; |
25 import android.util.AttributeSet; | 24 import android.util.AttributeSet; |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 } else { | 386 } else { |
388 ((ViewGroup) toolbar.getParent()).removeView(toolbar); | 387 ((ViewGroup) toolbar.getParent()).removeView(toolbar); |
389 MarginLayoutParams params = (MarginLayoutParams) getWrapperView().ge
tLayoutParams(); | 388 MarginLayoutParams params = (MarginLayoutParams) getWrapperView().ge
tLayoutParams(); |
390 params.bottomMargin = 0; | 389 params.bottomMargin = 0; |
391 } | 390 } |
392 } | 391 } |
393 | 392 |
394 private void updateSearchBoxOnScroll() { | 393 private void updateSearchBoxOnScroll() { |
395 if (mDisableUrlFocusChangeAnimations) return; | 394 if (mDisableUrlFocusChangeAnimations) return; |
396 | 395 |
| 396 float toolbarTransitionPercentage; |
| 397 // During startup the view may not be fully initialized, so we only calc
ulate the current |
| 398 // percentage if some basic view properties are sane. |
| 399 if (getWrapperView().getHeight() == 0 || mSearchBoxView.getTop() == 0) { |
| 400 toolbarTransitionPercentage = 0f; |
| 401 } else if (!mUseCardsUi) { |
| 402 toolbarTransitionPercentage = |
| 403 MathUtils.clamp(getVerticalScroll() / (float) mSearchBoxView
.getTop(), 0f, 1f); |
| 404 } else { |
| 405 if (!mRecyclerView.isFirstItemVisible()) { |
| 406 // getVerticalScroll is valid only for the RecyclerView if the f
irst item is |
| 407 // visible. Luckily, if the first item is not visible, we know t
he toolbar |
| 408 // transition should be 100%. |
| 409 toolbarTransitionPercentage = 1f; |
| 410 } else { |
| 411 final int scrollY = getVerticalScroll(); |
| 412 final int top = mSearchBoxView.getTop(); // Relative to mNewTab
PageLayout. |
| 413 final int transitionLength = getResources() |
| 414 .getDimensionPixelSize(R.dimen.ntp_search_box_transition
_length); |
| 415 |
| 416 // |scrollY - top| gives the distance the search bar is from the
top of the screen. |
| 417 toolbarTransitionPercentage = MathUtils.clamp( |
| 418 (scrollY - top + transitionLength) / (float) transitionL
ength, 0f, 1f); |
| 419 } |
| 420 } |
| 421 |
| 422 updateVisualsForToolbarTransition(toolbarTransitionPercentage); |
| 423 |
397 if (mSearchBoxScrollListener != null) { | 424 if (mSearchBoxScrollListener != null) { |
398 mSearchBoxScrollListener.onNtpScrollChanged(getToolbarTransitionPerc
entage()); | 425 mSearchBoxScrollListener.onNtpScrollChanged(toolbarTransitionPercent
age); |
399 } | 426 } |
400 } | 427 } |
401 | 428 |
402 /** | |
403 * Calculates the percentage (between 0 and 1) of the transition from the se
arch box to the | |
404 * omnibox at the top of the New Tab Page, which is determined by the amount
of scrolling and | |
405 * the position of the search box. | |
406 * | |
407 * @return the transition percentage | |
408 */ | |
409 private float getToolbarTransitionPercentage() { | |
410 // During startup the view may not be fully initialized, so we only calc
ulate the current | |
411 // percentage if some basic view properties (height of the containing vi
ew, position of the | |
412 // search box) are sane. | |
413 if (getWrapperView().getHeight() == 0) return 0f; | |
414 | |
415 int searchBoxTop = mSearchBoxView.getTop(); | |
416 if (searchBoxTop == 0) return 0f; | |
417 | |
418 // For all other calculations, add the search box padding, because it de
fines where the | |
419 // visible "border" of the search box is. | |
420 searchBoxTop += mSearchBoxView.getPaddingTop(); | |
421 | |
422 if (!mUseCardsUi) { | |
423 return MathUtils.clamp(getVerticalScroll() / (float) searchBoxTop, 0
f, 1f); | |
424 } | |
425 | |
426 if (!mRecyclerView.isFirstItemVisible()) { | |
427 // getVerticalScroll is valid only for the RecyclerView if the first
item is | |
428 // visible. If the first item is not visible, we know the toolbar tr
ansition | |
429 // should be 100%. | |
430 return 1f; | |
431 } | |
432 | |
433 final int scrollY = getVerticalScroll(); | |
434 final float transitionLength = | |
435 getResources().getDimension(R.dimen.ntp_search_box_transition_le
ngth); | |
436 | |
437 // |scrollY - searchBoxTop| gives the distance the search bar is from th
e top of the screen. | |
438 return MathUtils.clamp( | |
439 (scrollY - searchBoxTop + transitionLength) / transitionLength,
0f, 1f); | |
440 } | |
441 | |
442 private ViewGroup getWrapperView() { | 429 private ViewGroup getWrapperView() { |
443 return mUseCardsUi ? mRecyclerView : mScrollView; | 430 return mUseCardsUi ? mRecyclerView : mScrollView; |
444 } | 431 } |
445 | 432 |
446 /** | 433 /** |
447 * Get the number of listed items (visible or not) for the given type. | 434 * Get the number of listed items (visible or not) for the given type. |
448 * @param newTabPageListItemViewType the item type to count. | 435 * @param newTabPageListItemViewType the item type to count. |
449 */ | 436 */ |
450 public int getViewCountMatchingViewType( | 437 public int getViewCountMatchingViewType( |
451 @NewTabPageListItem.ViewType int newTabPageListItemViewType) { | 438 @NewTabPageListItem.ViewType int newTabPageListItemViewType) { |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 private void onUrlFocusAnimationChanged() { | 654 private void onUrlFocusAnimationChanged() { |
668 if (mDisableUrlFocusChangeAnimations) return; | 655 if (mDisableUrlFocusChangeAnimations) return; |
669 | 656 |
670 float percent = mSearchProviderHasLogo ? mUrlFocusChangePercent : 0; | 657 float percent = mSearchProviderHasLogo ? mUrlFocusChangePercent : 0; |
671 // Only apply the scrolling offset when not using the cards UI, as there
we will either snap | 658 // Only apply the scrolling offset when not using the cards UI, as there
we will either snap |
672 // to the top of the page (with scrolling offset 0), or snap to below th
e fold, where Most | 659 // to the top of the page (with scrolling offset 0), or snap to below th
e fold, where Most |
673 // Likely items are not visible anymore, so they will stay out of sight. | 660 // Likely items are not visible anymore, so they will stay out of sight. |
674 int scrollOffset = mUseCardsUi ? 0 : mScrollView.getScrollY(); | 661 int scrollOffset = mUseCardsUi ? 0 : mScrollView.getScrollY(); |
675 mNewTabPageLayout.setTranslationY(percent * (-mMostVisitedLayout.getTop(
) + scrollOffset | 662 mNewTabPageLayout.setTranslationY(percent * (-mMostVisitedLayout.getTop(
) + scrollOffset |
676 + mNewTabPageLayout.
getPaddingTop())); | 663 + mNewTabPageLayout.
getPaddingTop())); |
| 664 updateVisualsForToolbarTransition(percent); |
677 } | 665 } |
678 | 666 |
679 /** | 667 /** |
680 * Updates the opacity of the search box when scrolling. | 668 * Updates the opacity of the fake omnibox and Google logo when scrolling. |
681 * | 669 * @param transitionPercentage |
682 * @param alpha opacity (alpha) value to use. | |
683 */ | 670 */ |
684 public void setSearchBoxAlpha(float alpha) { | 671 private void updateVisualsForToolbarTransition(float transitionPercentage) { |
685 mSearchBoxView.setAlpha(alpha); | 672 // Complete the full alpha transition in the first 40% of the animation. |
686 } | 673 float searchUiAlpha = |
| 674 transitionPercentage >= 0.4f ? 0f : (0.4f - transitionPercentage
) * 2.5f; |
| 675 // Ensure there are no rounding issues when the animation percent is 0. |
| 676 if (transitionPercentage == 0f) searchUiAlpha = 1f; |
687 | 677 |
688 /** | 678 if (!mUseCardsUi) { |
689 * Updates the opacity of the search provider logo when scrolling. | 679 mSearchProviderLogoView.setAlpha(searchUiAlpha); |
690 * | 680 } |
691 * @param alpha opacity (alpha) value to use. | 681 mSearchBoxView.setAlpha(searchUiAlpha); |
692 */ | |
693 public void setSearchProviderLogoAlpha(float alpha) { | |
694 mSearchProviderLogoView.setAlpha(alpha); | |
695 } | 682 } |
696 | 683 |
697 /** | 684 /** |
698 * Get the bounds of the search box in relation to the top level NewTabPage
view. | 685 * Get the bounds of the search box in relation to the top level NewTabPage
view. |
699 * | 686 * |
700 * @param bounds The current drawing location of the search box. | 687 * @param originalBounds The bounding region of the search box without exter
nal transforms |
701 * @param translation The translation applied to the search box by the paren
t view hierarchy up | 688 * applied. The delta between this and the transforme
d bounds determines |
702 * to the NewTabPage view. | 689 * the amount of scroll applied to this view. |
| 690 * @param transformedBounds The bounding region of the search box including
any transforms |
| 691 * applied by the parent view hierarchy up to the N
ewTabPage view. |
| 692 * This more accurately reflects the current drawin
g location of the |
| 693 * search box. |
703 */ | 694 */ |
704 void getSearchBoxBounds(Rect bounds, Point translation) { | 695 void getSearchBoxBounds(Rect originalBounds, Rect transformedBounds) { |
705 int searchBoxX = (int) mSearchBoxView.getX(); | 696 int searchBoxX = (int) mSearchBoxView.getX(); |
706 int searchBoxY = (int) mSearchBoxView.getY(); | 697 int searchBoxY = (int) mSearchBoxView.getY(); |
707 | 698 |
708 bounds.set(searchBoxX + mSearchBoxView.getPaddingLeft(), | 699 originalBounds.set( |
| 700 searchBoxX + mSearchBoxView.getPaddingLeft(), |
709 searchBoxY + mSearchBoxView.getPaddingTop(), | 701 searchBoxY + mSearchBoxView.getPaddingTop(), |
710 searchBoxX + mSearchBoxView.getWidth() - mSearchBoxView.getPaddi
ngRight(), | 702 searchBoxX + mSearchBoxView.getWidth() - mSearchBoxView.getPaddi
ngRight(), |
711 searchBoxY + mSearchBoxView.getHeight() - mSearchBoxView.getPadd
ingBottom()); | 703 searchBoxY + mSearchBoxView.getHeight() - mSearchBoxView.getPadd
ingBottom()); |
712 | 704 |
713 translation.set(0, 0); | 705 transformedBounds.set(originalBounds); |
714 | |
715 View view = (View) mSearchBoxView.getParent(); | 706 View view = (View) mSearchBoxView.getParent(); |
716 while (view != null) { | 707 while (view != null) { |
717 translation.offset(-view.getScrollX(), -view.getScrollY()); | 708 transformedBounds.offset(-view.getScrollX(), -view.getScrollY()); |
718 if (view == this) break; | 709 if (view == this) break; |
719 translation.offset((int) view.getX(), (int) view.getY()); | 710 transformedBounds.offset((int) view.getX(), (int) view.getY()); |
720 view = (View) view.getParent(); | 711 view = (View) view.getParent(); |
721 } | 712 } |
722 bounds.offset(translation.x, translation.y); | |
723 } | 713 } |
724 | 714 |
725 /** | 715 /** |
726 * Sets the listener for search box scroll changes. | 716 * Sets the listener for search box scroll changes. |
727 * @param listener The listener to be notified on changes. | 717 * @param listener The listener to be notified on changes. |
728 */ | 718 */ |
729 void setSearchBoxScrollListener(OnSearchBoxScrollListener listener) { | 719 void setSearchBoxScrollListener(OnSearchBoxScrollListener listener) { |
730 mSearchBoxScrollListener = listener; | 720 mSearchBoxScrollListener = listener; |
731 if (mSearchBoxScrollListener != null) updateSearchBoxOnScroll(); | 721 if (mSearchBoxScrollListener != null) updateSearchBoxOnScroll(); |
732 } | 722 } |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1105 } | 1095 } |
1106 | 1096 |
1107 private int getVerticalScroll() { | 1097 private int getVerticalScroll() { |
1108 if (mUseCardsUi) { | 1098 if (mUseCardsUi) { |
1109 return mRecyclerView.computeVerticalScrollOffset(); | 1099 return mRecyclerView.computeVerticalScrollOffset(); |
1110 } else { | 1100 } else { |
1111 return mScrollView.getScrollY(); | 1101 return mScrollView.getScrollY(); |
1112 } | 1102 } |
1113 } | 1103 } |
1114 } | 1104 } |
OLD | NEW |