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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java

Issue 1947263003: Pin the snippets to the bottom of the page and introduce a peeking card to indicate to the user the… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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
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.Resources; 9 import android.content.res.Resources;
10 import android.graphics.Bitmap; 10 import android.graphics.Bitmap;
(...skipping 27 matching lines...) Expand all
38 import org.chromium.base.metrics.RecordUserAction; 38 import org.chromium.base.metrics.RecordUserAction;
39 import org.chromium.chrome.R; 39 import org.chromium.chrome.R;
40 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; 40 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
41 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallbac k; 41 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallbac k;
42 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; 42 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
43 import org.chromium.chrome.browser.ntp.LogoBridge.Logo; 43 import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
44 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver; 44 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
45 import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager; 45 import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager;
46 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; 46 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
47 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter; 47 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
48 import org.chromium.chrome.browser.ntp.cards.NewTabPageListItem;
48 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView; 49 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
49 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; 50 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
50 import org.chromium.chrome.browser.ntp.snippets.SnippetItemDecoration; 51 import org.chromium.chrome.browser.ntp.snippets.SnippetItemDecoration;
51 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge.SnippetsObserver; 52 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge.SnippetsObserver;
52 import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObse rver; 53 import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObse rver;
53 import org.chromium.chrome.browser.profiles.MostVisitedSites.ThumbnailCallback; 54 import org.chromium.chrome.browser.profiles.MostVisitedSites.ThumbnailCallback;
54 import org.chromium.chrome.browser.util.ViewUtils; 55 import org.chromium.chrome.browser.util.ViewUtils;
55 import org.chromium.chrome.browser.widget.RoundedIconGenerator; 56 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
56 import org.chromium.ui.base.DeviceFormFactor; 57 import org.chromium.ui.base.DeviceFormFactor;
57 58
(...skipping 11 matching lines...) Expand all
69 implements MostVisitedURLsObserver, OnLayoutChangeListener { 70 implements MostVisitedURLsObserver, OnLayoutChangeListener {
70 71
71 private static final int SHADOW_COLOR = 0x11000000; 72 private static final int SHADOW_COLOR = 0x11000000;
72 private static final long SNAP_SCROLL_DELAY_MS = 30; 73 private static final long SNAP_SCROLL_DELAY_MS = 30;
73 private static final String TAG = "Ntp"; 74 private static final String TAG = "Ntp";
74 75
75 /** 76 /**
76 * Indicates which UI mode we are using. Should be checked when manipulating some members, as 77 * Indicates which UI mode we are using. Should be checked when manipulating some members, as
77 * they may be unused or {@code null} depending on the mode. 78 * they may be unused or {@code null} depending on the mode.
78 */ 79 */
79 private boolean mUseCardsUi; 80 private static boolean USE_CARDS_UI;
May 2016/05/05 16:28:22 ALL_CAPS only for static final, otherwise use sAbc
Bernhard Bauer 2016/05/05 16:46:04 SHOUTING_CASE is only used for constants (which ar
mcwilliams 2016/05/05 17:39:47 Done.
mcwilliams 2016/05/05 17:39:47 Done.
80 81
81 // Note: Only one of these will be valid at a time, depending on if we are u sing the old NTP 82 // Note: Only one of these will be valid at a time, depending on if we are u sing the old NTP
82 // (NewTabPageScrollView) or the new NTP with cards (NewTabPageRecyclerView) . 83 // (NewTabPageScrollView) or the new NTP with cards (NewTabPageRecyclerView) .
83 private NewTabPageScrollView mScrollView; 84 private NewTabPageScrollView mScrollView;
84 private NewTabPageRecyclerView mRecyclerView; 85 private NewTabPageRecyclerView mRecyclerView;
85 86
86 private NewTabPageLayout mContentView; 87 private NewTabPageLayout mNewTabPageLayout;
87 private LogoView mSearchProviderLogoView; 88 private LogoView mSearchProviderLogoView;
88 private View mSearchBoxView; 89 private View mSearchBoxView;
89 private ImageView mVoiceSearchButton; 90 private ImageView mVoiceSearchButton;
90 private MostVisitedLayout mMostVisitedLayout; 91 private MostVisitedLayout mMostVisitedLayout;
91 private View mMostVisitedPlaceholder; 92 private View mMostVisitedPlaceholder;
92 private View mNoSearchLogoSpacer; 93 private View mNoSearchLogoSpacer;
93 94
94 /** Adapter for {@link #mRecyclerView}. Will be {@code null} when using the old UI */ 95 /** Adapter for {@link #mRecyclerView}. Will be {@code null} when using the old UI */
95 private NewTabPageAdapter mNtpAdapter; 96 private NewTabPageAdapter mNewTabPageAdapter;
96 97
97 private OnSearchBoxScrollListener mSearchBoxScrollListener; 98 private OnSearchBoxScrollListener mSearchBoxScrollListener;
98 99
99 private NewTabPageManager mManager; 100 private NewTabPageManager mManager;
100 private MostVisitedDesign mMostVisitedDesign; 101 private MostVisitedDesign mMostVisitedDesign;
101 private MostVisitedItem[] mMostVisitedItems; 102 private MostVisitedItem[] mMostVisitedItems;
102 private boolean mFirstShow = true; 103 private boolean mFirstShow = true;
103 private boolean mSearchProviderHasLogo = true; 104 private boolean mSearchProviderHasLogo = true;
104 private boolean mHasReceivedMostVisitedSites; 105 private boolean mHasReceivedMostVisitedSites;
105 private boolean mPendingSnapScroll; 106 private boolean mPendingSnapScroll;
106 107
107 /** 108 /**
108 * The number of asynchronous tasks that need to complete before the page is done loading. 109 * The number of asynchronous tasks that need to complete before the page is done loading.
109 * This starts at one to track when the view is finished attaching to the wi ndow. 110 * This starts at one to track when the view is finished attaching to the wi ndow.
110 */ 111 */
111 private int mPendingLoadTasks = 1; 112 private int mPendingLoadTasks = 1;
112 private boolean mLoadHasCompleted; 113 private boolean mLoadHasCompleted;
113 114
114 private float mUrlFocusChangePercent; 115 private float mUrlFocusChangePercent;
115 private boolean mDisableUrlFocusChangeAnimations; 116 private boolean mDisableUrlFocusChangeAnimations;
116 117
117 private boolean mSnapshotMostVisitedChanged; 118 private boolean mSnapshotMostVisitedChanged;
118 private int mSnapshotWidth; 119 private int mSnapshotWidth;
119 private int mSnapshotHeight; 120 private int mSnapshotHeight;
120 private int mSnapshotScrollY; 121 private int mSnapshotScrollY;
121 122
123 private int peekingCardVerticalScrollStart;
May 2016/05/05 16:28:22 Unused variable?
Bernhard Bauer 2016/05/05 16:46:04 Member variables should start with "m" (and contin
mcwilliams 2016/05/05 17:39:46 Done.
mcwilliams 2016/05/05 17:39:47 Very much used
124
122 /** 125 /**
123 * Manages the view interaction with the rest of the system. 126 * Manages the view interaction with the rest of the system.
124 */ 127 */
125 public interface NewTabPageManager extends MostVisitedItemManager { 128 public interface NewTabPageManager extends MostVisitedItemManager {
126 /** @return Whether the location bar is shown in the NTP. */ 129 /** @return Whether the location bar is shown in the NTP. */
127 boolean isLocationBarShownInNTP(); 130 boolean isLocationBarShownInNTP();
128 131
129 /** @return Whether voice search is enabled and the microphone should be shown. */ 132 /** @return Whether voice search is enabled and the microphone should be shown. */
130 boolean isVoiceSearchEnabled(); 133 boolean isVoiceSearchEnabled();
131 134
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 * @param manager NewTabPageManager used to perform various actions when the user interacts 267 * @param manager NewTabPageManager used to perform various actions when the user interacts
265 * with the page. 268 * with the page.
266 * @param searchProviderHasLogo Whether the search provider has a logo. 269 * @param searchProviderHasLogo Whether the search provider has a logo.
267 * @param useCardsUi Whether to use the new cards based UI or the old one. 270 * @param useCardsUi Whether to use the new cards based UI or the old one.
268 */ 271 */
269 public void initialize(NewTabPageManager manager, 272 public void initialize(NewTabPageManager manager,
270 boolean searchProviderHasLogo, boolean useCardsUi) { 273 boolean searchProviderHasLogo, boolean useCardsUi) {
271 mManager = manager; 274 mManager = manager;
272 ViewStub stub = (ViewStub) findViewById(R.id.new_tab_page_layout_stub); 275 ViewStub stub = (ViewStub) findViewById(R.id.new_tab_page_layout_stub);
273 276
274 mUseCardsUi = useCardsUi; 277 USE_CARDS_UI = useCardsUi;
275 if (mUseCardsUi) { 278 if (USE_CARDS_UI) {
276 stub.setLayoutResource(R.layout.new_tab_page_recycler_view); 279 stub.setLayoutResource(R.layout.new_tab_page_recycler_view);
277 mRecyclerView = (NewTabPageRecyclerView) stub.inflate(); 280 mRecyclerView = (NewTabPageRecyclerView) stub.inflate();
278 281
279 // Don't attach now, the recyclerView itself will determine when to do it. 282 // Don't attach now, the recyclerView itself will determine when to do it.
280 mContentView = (NewTabPageLayout) LayoutInflater.from(getContext()) 283 mNewTabPageLayout =
281 .inflate(R.layout.new_tab_page_layout, mRecyclerView, false) ; 284 (NewTabPageLayout) LayoutInflater.from(getContext())
285 .inflate(R.layout.new_tab_page_layout, mRecyclerView , false);
282 286
283 // Tailor the LayoutParams for the snippets UI, as the configuration in the XML is 287 // Tailor the LayoutParams for the snippets UI, as the configuration in the XML is
284 // made for the ScrollView UI. 288 // made for the ScrollView UI.
285 ViewGroup.LayoutParams params = mContentView.getLayoutParams(); 289 ViewGroup.LayoutParams params = mNewTabPageLayout.getLayoutParams();
286 params.height = ViewGroup.LayoutParams.WRAP_CONTENT; 290 params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
287 } else { 291 } else {
288 stub.setLayoutResource(R.layout.new_tab_page_scroll_view); 292 stub.setLayoutResource(R.layout.new_tab_page_scroll_view);
289 mScrollView = (NewTabPageScrollView) stub.inflate(); 293 mScrollView = (NewTabPageScrollView) stub.inflate();
290 mScrollView.enableBottomShadow(SHADOW_COLOR); 294 mScrollView.enableBottomShadow(SHADOW_COLOR);
291 mContentView = (NewTabPageLayout) findViewById(R.id.ntp_content); 295 mNewTabPageLayout = (NewTabPageLayout) findViewById(R.id.ntp_content );
292 } 296 }
293 297
294 mMostVisitedDesign = new MostVisitedDesign(getContext()); 298 mMostVisitedDesign = new MostVisitedDesign(getContext());
295 mMostVisitedLayout = 299 mMostVisitedLayout =
296 (MostVisitedLayout) mContentView.findViewById(R.id.most_visited_ layout); 300 (MostVisitedLayout) mNewTabPageLayout.findViewById(R.id.most_vis ited_layout);
297 mMostVisitedDesign.initMostVisitedLayout(mMostVisitedLayout, searchProvi derHasLogo); 301 mMostVisitedDesign.initMostVisitedLayout(mMostVisitedLayout, searchProvi derHasLogo);
298 302
299 mSearchProviderLogoView = (LogoView) mContentView.findViewById(R.id.sear ch_provider_logo); 303 mSearchProviderLogoView =
300 mSearchBoxView = mContentView.findViewById(R.id.search_box); 304 (LogoView) mNewTabPageLayout.findViewById(R.id.search_provider_l ogo);
301 mNoSearchLogoSpacer = mContentView.findViewById(R.id.no_search_logo_spac er); 305 mSearchBoxView = mNewTabPageLayout.findViewById(R.id.search_box);
306 mNoSearchLogoSpacer = mNewTabPageLayout.findViewById(R.id.no_search_logo _spacer);
302 307
303 final TextView searchBoxTextView = (TextView) mSearchBoxView 308 final TextView searchBoxTextView = (TextView) mSearchBoxView
304 .findViewById(R.id.search_box_text); 309 .findViewById(R.id.search_box_text);
305 String hintText = getResources().getString(R.string.search_or_type_url); 310 String hintText = getResources().getString(R.string.search_or_type_url);
306 311
307 if (!DeviceFormFactor.isTablet(getContext()) || manager.isFakeOmniboxTex tEnabledTablet()) { 312 if (!DeviceFormFactor.isTablet(getContext()) || manager.isFakeOmniboxTex tEnabledTablet()) {
308 searchBoxTextView.setHint(hintText); 313 searchBoxTextView.setHint(hintText);
309 } else { 314 } else {
310 searchBoxTextView.setContentDescription(hintText); 315 searchBoxTextView.setContentDescription(hintText);
311 } 316 }
(...skipping 13 matching lines...) Expand all
325 } 330 }
326 331
327 @Override 332 @Override
328 public void afterTextChanged(Editable s) { 333 public void afterTextChanged(Editable s) {
329 if (s.length() == 0) return; 334 if (s.length() == 0) return;
330 mManager.focusSearchBox(false, s.toString()); 335 mManager.focusSearchBox(false, s.toString());
331 searchBoxTextView.setText(""); 336 searchBoxTextView.setText("");
332 } 337 }
333 }); 338 });
334 339
335 mVoiceSearchButton = (ImageView) mContentView.findViewById(R.id.voice_se arch_button); 340 mVoiceSearchButton = (ImageView) mNewTabPageLayout.findViewById(R.id.voi ce_search_button);
336 mVoiceSearchButton.setOnClickListener(new View.OnClickListener() { 341 mVoiceSearchButton.setOnClickListener(new View.OnClickListener() {
337 @Override 342 @Override
338 public void onClick(View v) { 343 public void onClick(View v) {
339 mManager.focusSearchBox(true, null); 344 mManager.focusSearchBox(true, null);
340 } 345 }
341 }); 346 });
342 347
343 // Set up the toolbar 348 // Set up the toolbar
344 NewTabPageToolbar toolbar = (NewTabPageToolbar) findViewById(R.id.ntp_to olbar); 349 NewTabPageToolbar toolbar = (NewTabPageToolbar) findViewById(R.id.ntp_to olbar);
345 if (manager.isToolbarEnabled()) { 350 if (manager.isToolbarEnabled()) {
(...skipping 15 matching lines...) Expand all
361 mManager.navigateToInterests(); 366 mManager.navigateToInterests();
362 } 367 }
363 }); 368 });
364 369
365 // Set up interests 370 // Set up interests
366 if (manager.isInterestsEnabled()) { 371 if (manager.isInterestsEnabled()) {
367 toolbar.getInterestsButton().setVisibility(View.VISIBLE); 372 toolbar.getInterestsButton().setVisibility(View.VISIBLE);
368 } 373 }
369 } else { 374 } else {
370 ((ViewGroup) toolbar.getParent()).removeView(toolbar); 375 ((ViewGroup) toolbar.getParent()).removeView(toolbar);
371 if (!mUseCardsUi) { 376 if (!USE_CARDS_UI) {
372 // Only remove if we're using the old NTP view, the new one does not use a 377 // Only remove if we're using the old NTP view, the new one does not use a
373 // ScrollView 378 // ScrollView
374 FrameLayout.LayoutParams params = 379 FrameLayout.LayoutParams params =
375 (FrameLayout.LayoutParams) mScrollView.getLayoutParams() ; 380 (FrameLayout.LayoutParams) mScrollView.getLayoutParams() ;
376 params.bottomMargin = 0; 381 params.bottomMargin = 0;
377 mScrollView.setLayoutParams(params); 382 mScrollView.setLayoutParams(params);
378 } 383 }
379 } 384 }
380 385
381 addOnLayoutChangeListener(this); 386 addOnLayoutChangeListener(this);
382 setSearchProviderHasLogo(searchProviderHasLogo); 387 setSearchProviderHasLogo(searchProviderHasLogo);
383 388
384 mPendingLoadTasks++; 389 mPendingLoadTasks++;
385 mManager.setMostVisitedURLsObserver(this, 390 mManager.setMostVisitedURLsObserver(this,
386 mMostVisitedDesign.getNumberOfTiles(searchProviderHasLogo)); 391 mMostVisitedDesign.getNumberOfTiles(searchProviderHasLogo));
387 392
388 // Set up snippets 393 // Set up snippets
389 if (mUseCardsUi) { 394 if (USE_CARDS_UI) {
390 mNtpAdapter = new NewTabPageAdapter(mManager, mContentView); 395 mNewTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayo ut);
391 mRecyclerView.setAdapter(mNtpAdapter); 396 mRecyclerView.setAdapter(mNewTabPageAdapter);
397 mRecyclerView.setNewTabPageLayout(mNewTabPageLayout);
May 2016/05/05 16:28:22 I don't think this is necessary anymore
mcwilliams 2016/05/05 17:39:47 Done.
392 398
393 // Set up swipe-to-dismiss 399 // Set up swipe-to-dismiss
394 ItemTouchHelper helper = new ItemTouchHelper(mNtpAdapter.getItemTouc hCallbacks()); 400 ItemTouchHelper helper =
401 new ItemTouchHelper(mNewTabPageAdapter.getItemTouchCallbacks ());
395 helper.attachToRecyclerView(mRecyclerView); 402 helper.attachToRecyclerView(mRecyclerView);
396 403
397 NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACTION_SHOW N); 404 NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACTION_SHOW N);
398 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener( ) { 405 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener( ) {
399 private boolean mScrolledOnce = false; 406 private boolean mScrolledOnce = false;
400 @Override 407 @Override
401 public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 408 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
402 if (newState != RecyclerView.SCROLL_STATE_DRAGGING) return; 409 if (newState != RecyclerView.SCROLL_STATE_DRAGGING) return;
403 RecordUserAction.record("MobileNTP.Snippets.Scrolled"); 410 RecordUserAction.record("MobileNTP.Snippets.Scrolled");
404 if (mScrolledOnce) return; 411 if (mScrolledOnce) return;
405 mScrolledOnce = true; 412 mScrolledOnce = true;
406 NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACT ION_SCROLLED); 413 NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACT ION_SCROLLED);
407 } 414 }
408 }); 415 });
409 initializeSearchBoxRecyclerViewScrollHandling(); 416 initializeSearchBoxRecyclerViewScrollHandling();
410 mRecyclerView.addItemDecoration(new SnippetItemDecoration()); 417 mRecyclerView.addItemDecoration(new SnippetItemDecoration());
418 updatePeekingCard();
411 } else { 419 } else {
412 initializeSearchBoxScrollHandling(); 420 initializeSearchBoxScrollHandling();
413 } 421 }
414 } 422 }
415 423
416 private void updateSearchBoxOnScroll() { 424 private void updateSearchBoxOnScroll() {
417 if (mDisableUrlFocusChangeAnimations) return; 425 if (mDisableUrlFocusChangeAnimations) return;
418 426
419 float percentage = 0; 427 float percentage = 0;
420 // During startup the view may not be fully initialized, so we only calc ulate the current 428 // During startup the view may not be fully initialized, so we only calc ulate the current
421 // percentage if some basic view properties are sane. 429 // percentage if some basic view properties are sane.
422 View wrapperView = mUseCardsUi ? mRecyclerView : mScrollView; 430 View wrapperView = USE_CARDS_UI ? mRecyclerView : mScrollView;
423 if (wrapperView.getHeight() != 0 && mSearchBoxView.getTop() != 0) { 431 if (wrapperView.getHeight() != 0 && mSearchBoxView.getTop() != 0) {
424 // getVerticalScroll is valid only for the RecyclerView if the first item is visible. 432 // getVerticalScroll is valid only for the RecyclerView if the first item is visible.
425 // Luckily, if the first item is not visible, we know the toolbar tr ansition should 433 // Luckily, if the first item is not visible, we know the toolbar tr ansition should
426 // be 100%. 434 // be 100%.
427 if (mUseCardsUi && !mRecyclerView.isFirstItemVisible()) { 435 if (USE_CARDS_UI && !mRecyclerView.isFirstItemVisible()) {
428 percentage = 1f; 436 percentage = 1f;
429 } else { 437 } else {
430 int scrollY = getVerticalScroll(); 438 int scrollY = getVerticalScroll();
431 percentage = Math.max(0f, Math.min(1f, scrollY / (float) mSearch BoxView.getTop())); 439 percentage = Math.max(0f, Math.min(1f, scrollY / (float) mSearch BoxView.getTop()));
432 } 440 }
433 } 441 }
434 442
435 updateVisualsForToolbarTransition(percentage); 443 updateVisualsForToolbarTransition(percentage);
436 444
437 if (mSearchBoxScrollListener != null) { 445 if (mSearchBoxScrollListener != null) {
438 mSearchBoxScrollListener.onNtpScrollChanged(percentage); 446 mSearchBoxScrollListener.onNtpScrollChanged(percentage);
439 } 447 }
440 } 448 }
441 449
450 /**
451 * Calculate the peeking card/first snippet bleed and padding when scrolling if it is visible.
452 */
453 private void updatePeekingCard() {
Bernhard Bauer 2016/05/05 16:46:04 updatePeekingCardOnScroll()?
mcwilliams 2016/05/05 17:39:46 It is not just on scroll but also on initialize
454 // Get the first snippet that could display to make the peeking card tra nsition.
455 View firstSnippetView = null;
456 int recyclerViewSize = mNewTabPageAdapter.getItemCount();
May 2016/05/05 16:28:22 Not really the recyclerViewSize, it's the adapterS
mcwilliams 2016/05/05 17:39:46 Done.
457 for (int i = 0; i < recyclerViewSize; i++) {
458 if (mNewTabPageAdapter.getItemViewType(i) == NewTabPageListItem.VIEW _TYPE_SNIPPET) {
459 firstSnippetView = mRecyclerView.getLayoutManager().findViewByPo sition(i);
460 break;
461 }
462 }
463
464 // If first snippet exists change the parameters from peeking card with bleed to full page
465 // card when scrolling.
466 if (firstSnippetView != null && firstSnippetView.isShown()) {
467 // Value used for max peeking card height and padding.
468 int maxPadding = mNewTabPageLayout.getContext().getResources().getDi mensionPixelSize(
PEConn 2016/05/05 16:31:28 mNewTabPageLayout.getContext().getResources() can
mcwilliams 2016/05/05 17:39:46 Done.
469 R.dimen.snippets_padding_and_peeking_card_height);
470
471 // As the user scrolls, the bleed increases or decreases.
472 int bleed = maxPadding - (getVerticalScroll() - peekingCardVerticalS crollStart);
473
474 // Never let the bleed go into negative digits.
475 bleed = Math.max(bleed, 0);
476 // Never let the bleed be greater than the maxPadding.
477 bleed = Math.min(bleed, maxPadding);
478
479 // Modify the padding so as the margin increases, the padding decrea ses so the cards
480 // content does not shift.
481 firstSnippetView.setPadding(
482 maxPadding - bleed, maxPadding, maxPadding - bleed, maxPaddi ng);
PEConn 2016/05/05 16:31:28 Maybe add a comment that the 2nd and 4th arguments
mcwilliams 2016/05/05 17:39:46 Done.
483
484 // Modify the margin to grow the card from bleed to full width.
485 RecyclerView.LayoutParams params =
486 (RecyclerView.LayoutParams) firstSnippetView.getLayoutParams ();
487 params.leftMargin = bleed;
488 params.rightMargin = bleed;
489 }
490 }
491
492 /**
493 * Sets up scrolling when snippets are enabled. It adds scroll listeners and touch listeners to
PEConn 2016/05/05 16:31:28 I'd argue this comment is a bit too indepth - the
mcwilliams 2016/05/05 17:39:47 Acknowledged.
494 * the RecyclerView.
495 */
442 private void initializeSearchBoxRecyclerViewScrollHandling() { 496 private void initializeSearchBoxRecyclerViewScrollHandling() {
443 final Runnable mSnapScrollRunnable = new Runnable() { 497 final Runnable mSnapScrollRunnable = new Runnable() {
444 @Override 498 @Override
445 public void run() { 499 public void run() {
446 assert mPendingSnapScroll; 500 assert mPendingSnapScroll;
447 501
448 // These calculations only work if the first item is visible (si nce 502 // These calculations only work if the first item is visible (si nce
449 // computeVerticalScrollOffset only takes into account visible i tems). 503 // computeVerticalScrollOffset only takes into account visible i tems).
450 // Luckily, we only need to perform the calculations if the firs t item is visible. 504 // Luckily, we only need to perform the calculations if the firs t item is visible.
451 if (!mRecyclerView.isFirstItemVisible()) return; 505 if (!mRecyclerView.isFirstItemVisible()) return;
506
452 final int currentScroll = mRecyclerView.computeVerticalScrollOff set(); 507 final int currentScroll = mRecyclerView.computeVerticalScrollOff set();
453 508
454 // If snapping to Most Likely or to Articles, the omnibox will b e at the top of the 509 // If snapping to Most Likely or to Articles, the omnibox will b e at the top of the
455 // page, so offset the scroll so the scroll targets appear below it. 510 // page, so offset the scroll so the scroll targets appear below it.
456 final int omniBoxHeight = mContentView.getPaddingTop(); 511 final int omniBoxHeight = mNewTabPageLayout.getPaddingTop();
457 final int topOfMostLikelyScroll = mMostVisitedLayout.getTop() - omniBoxHeight; 512 final int topOfMostLikelyScroll = mMostVisitedLayout.getTop() - omniBoxHeight;
458 final int topOfSnippetsScroll = mContentView.getHeight() - omniB oxHeight; 513 final int topOfSnippetsScroll = mNewTabPageLayout.getHeight() - omniBoxHeight;
459 514
460 assert currentScroll >= 0; 515 assert currentScroll >= 0;
461 // Do not do any scrolling if the user is currently viewing arti cles. 516 // Do not do any scrolling if the user is currently viewing arti cles.
462 if (currentScroll > topOfSnippetsScroll) return; 517 if (currentScroll > topOfSnippetsScroll) return;
463 518
464 // If Most Likely is fully visible when we are scrolled to the t op, we have two 519 // If Most Likely is fully visible when we are scrolled to the t op, we have two
465 // snap points: the Top and Articles. 520 // snap points: the Top and Articles.
466 // If not, we have three snap points, the Top, Most Likely and A rticles. 521 // If not, we have three snap points, the Top, Most Likely and A rticles.
467 boolean snapToMostLikely = 522 boolean snapToMostLikely =
468 mRecyclerView.getHeight() < mMostVisitedLayout.getBottom (); 523 mRecyclerView.getHeight() < mMostVisitedLayout.getBottom ();
469 524
470 int targetScroll; 525 int targetScroll;
471 if (currentScroll < mContentView.getHeight() / 3) { 526 if (currentScroll < mNewTabPageLayout.getHeight() / 3) {
472 // In either case, if in the top 1/3 of the original NTP, sn ap to the top. 527 // In either case, if in the top 1/3 of the original NTP, sn ap to the top.
473 targetScroll = 0; 528 targetScroll = 0;
474 } else if (snapToMostLikely && currentScroll < mContentView.getH eight() * 2 / 3) { 529 } else if (
530 snapToMostLikely && currentScroll < mNewTabPageLayout.ge tHeight() * 2 / 3) {
May 2016/05/05 16:28:22 unnecessary line break
mcwilliams 2016/05/05 17:39:47 If I don't line break it is over 100 chars?
Bernhard Bauer 2016/05/05 18:04:40 I think what May meant was that breaking right aft
mcwilliams 2016/05/05 18:21:11 Done.
475 // If in the middle 1/3 and we are snapping to Most Likely, snap to it. 531 // If in the middle 1/3 and we are snapping to Most Likely, snap to it.
476 targetScroll = topOfMostLikelyScroll; 532 targetScroll = topOfMostLikelyScroll;
477 } else { 533 } else {
478 // Otherwise, snap to the Articles. 534 // Otherwise, snap to the Articles.
479 targetScroll = topOfSnippetsScroll; 535 targetScroll = topOfSnippetsScroll;
480 } 536 }
481 537
482 mRecyclerView.smoothScrollBy(0, targetScroll - currentScroll); 538 mRecyclerView.smoothScrollBy(0, targetScroll - currentScroll);
539
540 // Set the peeking card vertical scroll start for the snapped vi ew.
541 peekingCardVerticalScrollStart = targetScroll;
542
483 mPendingSnapScroll = false; 543 mPendingSnapScroll = false;
484 } 544 }
485 }; 545 };
486 546
487 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 547 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
488 @Override 548 @Override
489 public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 549 public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
490 if (mPendingSnapScroll) { 550 if (mPendingSnapScroll) {
491 mRecyclerView.removeCallbacks(mSnapScrollRunnable); 551 mRecyclerView.removeCallbacks(mSnapScrollRunnable);
492 mRecyclerView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_D ELAY_MS); 552 mRecyclerView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_D ELAY_MS);
493 } 553 }
494 updateSearchBoxOnScroll(); 554 updateSearchBoxOnScroll();
555 updatePeekingCard();
495 } 556 }
496 }); 557 });
497 558
498 mRecyclerView.setOnTouchListener(new OnTouchListener() { 559 mRecyclerView.setOnTouchListener(new OnTouchListener() {
499 @Override 560 @Override
500 @SuppressLint("ClickableViewAccessibility") 561 @SuppressLint("ClickableViewAccessibility")
501 public boolean onTouch(View v, MotionEvent event) { 562 public boolean onTouch(View v, MotionEvent event) {
502 mRecyclerView.removeCallbacks(mSnapScrollRunnable); 563 mRecyclerView.removeCallbacks(mSnapScrollRunnable);
503 564
504 if (event.getActionMasked() == MotionEvent.ACTION_CANCEL 565 if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
505 || event.getActionMasked() == MotionEvent.ACTION_UP) { 566 || event.getActionMasked() == MotionEvent.ACTION_UP) {
506 mPendingSnapScroll = true; 567 mPendingSnapScroll = true;
507 mRecyclerView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_D ELAY_MS); 568 mRecyclerView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_D ELAY_MS);
508 } else { 569 } else {
509 mPendingSnapScroll = false; 570 mPendingSnapScroll = false;
510 } 571 }
511 return false; 572 return false;
512 } 573 }
513 }); 574 });
514 } 575 }
515 576
577 /**
578 * Sets up scrolling when snippets are disabled. It ads scroll and touch lis teners to the scroll
PEConn 2016/05/05 16:31:28 *adds
Bernhard Bauer 2016/05/05 16:46:04 Nit: "adds"
mcwilliams 2016/05/05 17:39:47 Done.
mcwilliams 2016/05/05 17:39:47 Done.
579 * view.
580 */
516 private void initializeSearchBoxScrollHandling() { 581 private void initializeSearchBoxScrollHandling() {
517 final Runnable mSnapScrollRunnable = new Runnable() { 582 final Runnable mSnapScrollRunnable = new Runnable() {
518 @Override 583 @Override
519 public void run() { 584 public void run() {
520 if (!mPendingSnapScroll) return; 585 if (!mPendingSnapScroll) return;
521 int scrollY = mScrollView.getScrollY(); 586 int scrollY = mScrollView.getScrollY();
522 int dividerTop = mMostVisitedLayout.getTop() - mContentView.getP addingTop(); 587 int dividerTop = mMostVisitedLayout.getTop() - mNewTabPageLayout .getPaddingTop();
523 if (scrollY > 0 && scrollY < dividerTop) { 588 if (scrollY > 0 && scrollY < dividerTop) {
524 mScrollView.smoothScrollTo(0, scrollY < (dividerTop / 2) ? 0 : dividerTop); 589 mScrollView.smoothScrollTo(0, scrollY < (dividerTop / 2) ? 0 : dividerTop);
525 } 590 }
526 mPendingSnapScroll = false; 591 mPendingSnapScroll = false;
527 } 592 }
528 }; 593 };
529 mScrollView.setOnScrollListener(new NewTabPageScrollView.OnScrollListene r() { 594 mScrollView.setOnScrollListener(new NewTabPageScrollView.OnScrollListene r() {
530 @Override 595 @Override
531 public void onScrollChanged(int l, int t, int oldl, int oldt) { 596 public void onScrollChanged(int l, int t, int oldl, int oldt) {
532 if (mPendingSnapScroll) { 597 if (mPendingSnapScroll) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 public void setSearchProviderHasLogo(boolean hasLogo) { 661 public void setSearchProviderHasLogo(boolean hasLogo) {
597 if (hasLogo == mSearchProviderHasLogo) return; 662 if (hasLogo == mSearchProviderHasLogo) return;
598 mSearchProviderHasLogo = hasLogo; 663 mSearchProviderHasLogo = hasLogo;
599 664
600 mMostVisitedDesign.setSearchProviderHasLogo(mMostVisitedLayout, hasLogo) ; 665 mMostVisitedDesign.setSearchProviderHasLogo(mMostVisitedLayout, hasLogo) ;
601 666
602 if (!hasLogo) setUrlFocusChangeAnimationPercentInternal(0); 667 if (!hasLogo) setUrlFocusChangeAnimationPercentInternal(0);
603 668
604 // Hide or show all the views above the Most Visited items. 669 // Hide or show all the views above the Most Visited items.
605 int visibility = hasLogo ? View.VISIBLE : View.GONE; 670 int visibility = hasLogo ? View.VISIBLE : View.GONE;
606 int childCount = mContentView.getChildCount(); 671 int childCount = mNewTabPageLayout.getChildCount();
607 for (int i = 0; i < childCount; i++) { 672 for (int i = 0; i < childCount; i++) {
608 View child = mContentView.getChildAt(i); 673 View child = mNewTabPageLayout.getChildAt(i);
609 if (child == mMostVisitedLayout) break; 674 if (child == mMostVisitedLayout) break;
610 // Don't change the visibility of a ViewStub as that will automagica lly inflate it. 675 // Don't change the visibility of a ViewStub as that will automagica lly inflate it.
611 if (child instanceof ViewStub) continue; 676 if (child instanceof ViewStub) continue;
612 child.setVisibility(visibility); 677 child.setVisibility(visibility);
613 } 678 }
614 679
615 updateMostVisitedPlaceholderVisibility(); 680 updateMostVisitedPlaceholderVisibility();
616 681
617 if (hasLogo) setUrlFocusChangeAnimationPercent(mUrlFocusChangePercent); 682 if (hasLogo) setUrlFocusChangeAnimationPercent(mUrlFocusChangePercent);
618 mSnapshotMostVisitedChanged = true; 683 mSnapshotMostVisitedChanged = true;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 745
681 /** 746 /**
682 * Unconditionally sets the percentage the URL is focused during an animatio n, without updating 747 * Unconditionally sets the percentage the URL is focused during an animatio n, without updating
683 * mUrlFocusChangePercent. 748 * mUrlFocusChangePercent.
684 * @see #setUrlFocusChangeAnimationPercent 749 * @see #setUrlFocusChangeAnimationPercent
685 */ 750 */
686 private void setUrlFocusChangeAnimationPercentInternal(float percent) { 751 private void setUrlFocusChangeAnimationPercentInternal(float percent) {
687 // Only apply the scrolling offset when not using the cards UI, as there we will either snap 752 // Only apply the scrolling offset when not using the cards UI, as there we will either snap
688 // to the top of the page (with scrolling offset 0), or snap to below th e fold, where Most 753 // to the top of the page (with scrolling offset 0), or snap to below th e fold, where Most
689 // Likely items are not visible anymore, so they will stay out of sight. 754 // Likely items are not visible anymore, so they will stay out of sight.
690 int scrollOffset = mUseCardsUi ? 0 : mScrollView.getScrollY(); 755 int scrollOffset = USE_CARDS_UI ? 0 : mScrollView.getScrollY();
691 mContentView.setTranslationY(percent 756 mNewTabPageLayout.setTranslationY(percent * (-mMostVisitedLayout.getTop( ) + scrollOffset
692 * (-mMostVisitedLayout.getTop() + scrollOffset + mContentView.ge tPaddingTop())); 757 + mNewTabPageLayout. getPaddingTop()));
693 updateVisualsForToolbarTransition(percent); 758 updateVisualsForToolbarTransition(percent);
694 } 759 }
695 760
761 /**
762 * Updates the opacity of the fake omnibox and Google logo when scrolling.
763 * @param transitionPercentage
764 */
696 private void updateVisualsForToolbarTransition(float transitionPercentage) { 765 private void updateVisualsForToolbarTransition(float transitionPercentage) {
697 // Complete the full alpha transition in the first 40% of the animation. 766 // Complete the full alpha transition in the first 40% of the animation.
698 float searchUiAlpha = 767 float searchUiAlpha =
699 transitionPercentage >= 0.4f ? 0f : (0.4f - transitionPercentage ) * 2.5f; 768 transitionPercentage >= 0.4f ? 0f : (0.4f - transitionPercentage ) * 2.5f;
700 // Ensure there are no rounding issues when the animation percent is 0. 769 // Ensure there are no rounding issues when the animation percent is 0.
701 if (transitionPercentage == 0f) searchUiAlpha = 1f; 770 if (transitionPercentage == 0f) searchUiAlpha = 1f;
702 771
703 mSearchProviderLogoView.setAlpha(searchUiAlpha); 772 mSearchProviderLogoView.setAlpha(searchUiAlpha);
704 mSearchBoxView.setAlpha(searchUiAlpha); 773 mSearchBoxView.setAlpha(searchUiAlpha);
705 } 774 }
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 } 955 }
887 956
888 mHasReceivedMostVisitedSites = true; 957 mHasReceivedMostVisitedSites = true;
889 updateMostVisitedPlaceholderVisibility(); 958 updateMostVisitedPlaceholderVisibility();
890 959
891 if (isInitialLoad) { 960 if (isInitialLoad) {
892 loadTaskCompleted(); 961 loadTaskCompleted();
893 // The page contents are initially hidden; otherwise they'll be draw n centered on the 962 // The page contents are initially hidden; otherwise they'll be draw n centered on the
894 // page before the most visited sites are available and then jump up wards to make space 963 // page before the most visited sites are available and then jump up wards to make space
895 // once the most visited sites are available. 964 // once the most visited sites are available.
896 mContentView.setVisibility(View.VISIBLE); 965 mNewTabPageLayout.setVisibility(View.VISIBLE);
897 } 966 }
898 mSnapshotMostVisitedChanged = true; 967 mSnapshotMostVisitedChanged = true;
899 } 968 }
900 969
901 @Override 970 @Override
902 public void onPopularURLsAvailable( 971 public void onPopularURLsAvailable(
903 String[] urls, String[] faviconUrls, String[] largeIconUrls) { 972 String[] urls, String[] faviconUrls, String[] largeIconUrls) {
904 for (int i = 0; i < urls.length; i++) { 973 for (int i = 0; i < urls.length; i++) {
905 final String url = urls[i]; 974 final String url = urls[i];
906 boolean useLargeIcon = !largeIconUrls[i].isEmpty(); 975 boolean useLargeIcon = !largeIconUrls[i].isEmpty();
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 if (item.getUrl().equals(url)) { 1136 if (item.getUrl().equals(url)) {
1068 LargeIconCallback iconCallback = new LargeIconCallbackImpl( 1137 LargeIconCallback iconCallback = new LargeIconCallbackImpl(
1069 item, (MostVisitedItemView) item.getView(), false); 1138 item, (MostVisitedItemView) item.getView(), false);
1070 mManager.getLargeIconForUrl(url, mMinIconSize, iconCallback) ; 1139 mManager.getLargeIconForUrl(url, mMinIconSize, iconCallback) ;
1071 break; 1140 break;
1072 } 1141 }
1073 } 1142 }
1074 } 1143 }
1075 } 1144 }
1076 1145
1146 @Override
1147 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1148 // Set the parent scroll view port height in the layout.
1149 if (mNewTabPageLayout != null) {
1150 mNewTabPageLayout.setParentScrollViewportHeight(MeasureSpec.getSize( heightMeasureSpec));
May 2016/05/05 16:28:22 If we're doing this here, do we still need the mNe
mcwilliams 2016/05/05 17:39:47 No, removed
1151 }
1152 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
1153 }
1154
1077 private int getVerticalScroll() { 1155 private int getVerticalScroll() {
1078 if (mUseCardsUi) { 1156 if (USE_CARDS_UI) {
1079 return mRecyclerView.computeVerticalScrollOffset(); 1157 return mRecyclerView.computeVerticalScrollOffset();
1080 } else { 1158 } else {
1081 return mScrollView.getScrollY(); 1159 return mScrollView.getScrollY();
1082 } 1160 }
1083 } 1161 }
1162
1163 /**
1164 * Are snippets currently enabled.
1165 * @return
1166 */
1167 public static boolean isUseCardsUiEnabled() {
1168 return USE_CARDS_UI;
PEConn 2016/05/05 16:31:28 What if the NewTabPageView hasn't been initialized
mcwilliams 2016/05/05 17:39:47 Done.
1169 }
1084 } 1170 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698