Index: chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPageView.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPageView.java |
deleted file mode 100644 |
index 98cfe1146cf7daba402c45278f272d0f5cdaa06f..0000000000000000000000000000000000000000 |
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/NewTabPageView.java |
+++ /dev/null |
@@ -1,967 +0,0 @@ |
-// Copyright 2015 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-package org.chromium.chrome.browser.ntp; |
- |
-import android.annotation.SuppressLint; |
-import android.content.Context; |
-import android.content.res.Resources; |
-import android.graphics.Bitmap; |
-import android.graphics.Canvas; |
-import android.graphics.Rect; |
-import android.graphics.drawable.BitmapDrawable; |
-import android.net.Uri; |
-import android.os.Build; |
-import android.support.v4.graphics.drawable.RoundedBitmapDrawable; |
-import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; |
-import android.text.Editable; |
-import android.text.TextUtils; |
-import android.text.TextWatcher; |
-import android.text.method.LinkMovementMethod; |
-import android.text.style.ClickableSpan; |
-import android.util.AttributeSet; |
-import android.view.LayoutInflater; |
-import android.view.MotionEvent; |
-import android.view.View; |
-import android.view.View.OnLayoutChangeListener; |
-import android.view.ViewGroup; |
-import android.view.ViewStub; |
-import android.widget.Button; |
-import android.widget.FrameLayout; |
-import android.widget.ImageView; |
-import android.widget.TextView; |
- |
-import org.chromium.base.CommandLine; |
-import org.chromium.base.FieldTrialList; |
-import org.chromium.base.VisibleForTesting; |
-import org.chromium.base.metrics.RecordHistogram; |
-import org.chromium.chrome.R; |
-import org.chromium.chrome.browser.ChromeSwitches; |
-import org.chromium.chrome.browser.LogoBridge.Logo; |
-import org.chromium.chrome.browser.LogoBridge.LogoObserver; |
-import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; |
-import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; |
-import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager; |
-import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; |
-import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver; |
-import org.chromium.chrome.browser.profiles.MostVisitedSites.ThumbnailCallback; |
-import org.chromium.chrome.browser.util.FeatureUtilities; |
-import org.chromium.chrome.browser.util.ViewUtils; |
-import org.chromium.chrome.browser.widget.RoundedIconGenerator; |
-import org.chromium.ui.text.SpanApplier; |
-import org.chromium.ui.text.SpanApplier.SpanInfo; |
- |
-import java.util.Locale; |
- |
-/** |
- * The native new tab page, represented by some basic data such as title and url, and an Android |
- * View that displays the page. |
- */ |
-public class NewTabPageView extends FrameLayout |
- implements MostVisitedURLsObserver, OnLayoutChangeListener { |
- |
- static final int MAX_MOST_VISITED_SITES = 12; |
- private static final int SHADOW_COLOR = 0x11000000; |
- private static final long SNAP_SCROLL_DELAY_MS = 30; |
- |
- private static final String ICON_NTP_FIELD_TRIAL_NAME = "IconNTP"; |
- private static final String ICON_NTP_ENABLED_GROUP = "Enabled"; |
- |
- private ViewGroup mContentView; |
- private NewTabScrollView mScrollView; |
- private LogoView mSearchProviderLogoView; |
- private View mSearchBoxView; |
- private TextView mSearchBoxTextView; |
- private ImageView mVoiceSearchButton; |
- private ViewGroup mMostVisitedLayout; |
- private View mMostVisitedPlaceholder; |
- private View mOptOutView; |
- private View mNoSearchLogoSpacer; |
- |
- private OnSearchBoxScrollListener mSearchBoxScrollListener; |
- |
- private NewTabPageManager mManager; |
- private MostVisitedDesign mMostVisitedDesign; |
- private MostVisitedItem[] mMostVisitedItems; |
- private boolean mFirstShow = true; |
- private boolean mSearchProviderHasLogo = true; |
- private boolean mHasReceivedMostVisitedSites; |
- private boolean mPendingSnapScroll; |
- |
- /** |
- * The number of asynchronous tasks that need to complete before the page is done loading. |
- * This starts at one to track when the view is finished attaching to the window. |
- */ |
- private int mPendingLoadTasks = 1; |
- private boolean mLoadHasCompleted; |
- |
- private float mUrlFocusChangePercent; |
- private boolean mDisableUrlFocusChangeAnimations; |
- |
- private boolean mSnapshotMostVisitedChanged; |
- private int mSnapshotWidth; |
- private int mSnapshotHeight; |
- private int mSnapshotScrollY; |
- |
- /** |
- * Manages the view interaction with the rest of the system. |
- */ |
- public interface NewTabPageManager extends MostVisitedItemManager { |
- /** @return Whether the location bar is shown in the NTP. */ |
- boolean isLocationBarShownInNTP(); |
- |
- /** @return Whether the document mode opt out promo should be shown. */ |
- boolean shouldShowOptOutPromo(); |
- |
- /** Called when the document mode opt out promo is shown. */ |
- void optOutPromoShown(); |
- |
- /** Called when the user clicks "settings" or "ok, got it" on the opt out promo. */ |
- void optOutPromoClicked(boolean settingsClicked); |
- |
- /** Opens the bookmarks page in the current tab. */ |
- void navigateToBookmarks(); |
- |
- /** Opens the recent tabs page in the current tab. */ |
- void navigateToRecentTabs(); |
- |
- /** |
- * Animates the search box up into the omnibox and bring up the keyboard. |
- * @param beginVoiceSearch Whether to begin a voice search. |
- * @param pastedText Text to paste in the omnibox after it's been focused. May be null. |
- */ |
- void focusSearchBox(boolean beginVoiceSearch, String pastedText); |
- |
- /** |
- * Gets the list of most visited sites. |
- * @param observer The observer to be notified with the list of sites. |
- * @param numResults The maximum number of sites to retrieve. |
- */ |
- void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults); |
- |
- /** |
- * Gets a cached thumbnail of a URL. |
- * @param url The URL whose thumbnail is being retrieved. |
- * @param thumbnailCallback The callback to be notified when the thumbnail is available. |
- */ |
- void getURLThumbnail(String url, ThumbnailCallback thumbnailCallback); |
- |
- /** |
- * Gets the favicon image for a given URL. |
- * @param url The URL of the site whose favicon is being requested. |
- * @param size The desired size of the favicon in pixels. |
- * @param faviconCallback The callback to be notified when the favicon is available. |
- */ |
- void getLocalFaviconImageForURL( |
- String url, int size, FaviconImageCallback faviconCallback); |
- |
- /** |
- * Gets the large icon (e.g. favicon or touch icon) for a given URL. |
- * @param url The URL of the site whose icon is being requested. |
- * @param size The desired size of the icon in pixels. |
- * @param callback The callback to be notified when the icon is available. |
- */ |
- void getLargeIconForUrl(String url, int size, LargeIconCallback callback); |
- |
- /** |
- * Navigates to a URL chosen by the search provider when the user clicks on the logo. |
- */ |
- void openLogoLink(); |
- |
- /** |
- * Gets the default search provider's logo and calls logoObserver with the result. |
- * @param logoObserver The callback to notify when the logo is available. |
- */ |
- void getSearchProviderLogo(LogoObserver logoObserver); |
- |
- /** |
- * Called when the NTP has completely finished loading (all views will be inflated |
- * and any dependent resources will have been loaded). |
- */ |
- void onLoadingComplete(); |
- } |
- |
- /** |
- * Returns a title suitable for display for a link (e.g. a most visited item). If |title| is |
- * non-empty, this simply returns it. Otherwise, returns a shortened form of the URL. |
- */ |
- static String getTitleForDisplay(String title, String url) { |
- if (TextUtils.isEmpty(title) && url != null) { |
- Uri uri = Uri.parse(url); |
- String host = uri.getHost(); |
- String path = uri.getPath(); |
- if (host == null) host = ""; |
- if (TextUtils.isEmpty(path) || path.equals("/")) path = ""; |
- title = host + path; |
- } |
- return title; |
- } |
- |
- /** |
- * Default constructor required for XML inflation. |
- */ |
- public NewTabPageView(Context context, AttributeSet attrs) { |
- super(context, attrs); |
- } |
- |
- private boolean isIconNtpEnabled() { |
- // Query the field trial state first, to ensure that UMA reports the correct group. |
- String fieldTrialGroup = FieldTrialList.findFullName(ICON_NTP_FIELD_TRIAL_NAME); |
- CommandLine commandLine = CommandLine.getInstance(); |
- if (commandLine.hasSwitch(ChromeSwitches.DISABLE_ICON_NTP)) return false; |
- if (commandLine.hasSwitch(ChromeSwitches.ENABLE_ICON_NTP)) return true; |
- return fieldTrialGroup.equals(ICON_NTP_ENABLED_GROUP); |
- } |
- |
- /** |
- * Initializes the NTP. This must be called immediately after inflation, before this object is |
- * used in any other way. |
- * |
- * @param manager NewTabPageManager used to perform various actions when the user interacts |
- * with the page. |
- * @param isSingleUrlBarMode Whether the NTP is in single URL bar mode. |
- * @param searchProviderHasLogo Whether the search provider has a logo. |
- */ |
- public void initialize(NewTabPageManager manager, boolean isSingleUrlBarMode, |
- boolean searchProviderHasLogo) { |
- mManager = manager; |
- |
- mScrollView = (NewTabScrollView) findViewById(R.id.ntp_scrollview); |
- mScrollView.enableBottomShadow(SHADOW_COLOR); |
- mContentView = (ViewGroup) findViewById(R.id.ntp_content); |
- |
- mMostVisitedDesign = isIconNtpEnabled() |
- ? new IconMostVisitedDesign(getContext()) |
- : new ThumbnailMostVisitedDesign(getContext()); |
- ViewStub mostVisitedLayoutStub = (ViewStub) findViewById(R.id.most_visited_layout_stub); |
- mostVisitedLayoutStub.setLayoutResource(mMostVisitedDesign.getMostVisitedLayoutId()); |
- mMostVisitedLayout = (ViewGroup) mostVisitedLayoutStub.inflate(); |
- |
- mSearchProviderLogoView = (LogoView) findViewById(R.id.search_provider_logo); |
- mSearchBoxView = findViewById(R.id.search_box); |
- mNoSearchLogoSpacer = findViewById(R.id.no_search_logo_spacer); |
- |
- mSearchBoxTextView = (TextView) mSearchBoxView.findViewById(R.id.search_box_text); |
- String hintText = getResources().getString(R.string.search_or_type_url); |
- if (isSingleUrlBarMode) { |
- mSearchBoxTextView.setHint(hintText); |
- } else { |
- mSearchBoxTextView.setContentDescription(hintText); |
- } |
- mSearchBoxTextView.setOnClickListener(new View.OnClickListener() { |
- @Override |
- public void onClick(View v) { |
- mManager.focusSearchBox(false, null); |
- } |
- }); |
- mSearchBoxTextView.addTextChangedListener(new TextWatcher() { |
- @Override |
- public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
- } |
- |
- @Override |
- public void onTextChanged(CharSequence s, int start, int before, int count) { |
- } |
- |
- @Override |
- public void afterTextChanged(Editable s) { |
- if (s.length() == 0) return; |
- mManager.focusSearchBox(false, s.toString()); |
- mSearchBoxTextView.setText(""); |
- } |
- }); |
- |
- mVoiceSearchButton = (ImageView) findViewById(R.id.voice_search_button); |
- mVoiceSearchButton.setOnClickListener(new View.OnClickListener() { |
- @Override |
- public void onClick(View v) { |
- mManager.focusSearchBox(true, null); |
- } |
- }); |
- |
- NewTabPageToolbar toolbar = (NewTabPageToolbar) findViewById(R.id.ntp_toolbar); |
- toolbar.getRecentTabsButton().setOnClickListener(new View.OnClickListener() { |
- @Override |
- public void onClick(View v) { |
- mManager.navigateToRecentTabs(); |
- } |
- }); |
- toolbar.getBookmarksButton().setOnClickListener(new View.OnClickListener() { |
- @Override |
- public void onClick(View v) { |
- mManager.navigateToBookmarks(); |
- } |
- }); |
- |
- initializeSearchBoxScrollHandling(); |
- addOnLayoutChangeListener(this); |
- setSearchProviderHasLogo(searchProviderHasLogo); |
- |
- mPendingLoadTasks++; |
- mManager.setMostVisitedURLsObserver(this, |
- mMostVisitedDesign.getNumberOfTiles(searchProviderHasLogo)); |
- |
- if (mManager.shouldShowOptOutPromo()) showOptOutPromo(); |
- } |
- |
- private int getTabsMovedIllustration() { |
- switch (Build.MANUFACTURER.toLowerCase(Locale.US)) { |
- case "samsung": |
- return R.drawable.tabs_moved_samsung; |
- case "htc": |
- return R.drawable.tabs_moved_htc; |
- default: |
- return R.drawable.tabs_moved_nexus; |
- } |
- } |
- |
- private void showOptOutPromo() { |
- ViewStub optOutPromoStub = (ViewStub) findViewById(R.id.opt_out_promo_stub); |
- mOptOutView = optOutPromoStub.inflate(); |
- // Fill in opt-out text with Settings link |
- TextView optOutText = (TextView) mOptOutView.findViewById(R.id.opt_out_text); |
- |
- ClickableSpan settingsLink = new ClickableSpan() { |
- @Override |
- public void onClick(View view) { |
- mManager.optOutPromoClicked(true); |
- } |
- |
- // Change link formatting to use our blue control color and no underline |
- @Override |
- public void updateDrawState(android.text.TextPaint textPaint) { |
- textPaint.setColor(getContext().getResources().getColor( |
- R.color.light_active_color)); |
- textPaint.setUnderlineText(false); |
- } |
- }; |
- |
- optOutText.setText(SpanApplier.applySpans( |
- getContext().getString(R.string.tabs_and_apps_opt_out_text), |
- new SpanInfo("<link>", "</link>", settingsLink))); |
- optOutText.setMovementMethod(LinkMovementMethod.getInstance()); |
- |
- ImageView illustration = (ImageView) mOptOutView.findViewById(R.id.tabs_moved_illustration); |
- illustration.setImageResource(getTabsMovedIllustration()); |
- |
- mOptOutView.setVisibility(View.VISIBLE); |
- mMostVisitedLayout.setVisibility(View.GONE); |
- |
- Button gotItButton = (Button) mOptOutView.findViewById(R.id.got_it_button); |
- gotItButton.setOnClickListener(new View.OnClickListener() { |
- @Override |
- public void onClick(View v) { |
- mOptOutView.setVisibility(View.GONE); |
- mMostVisitedLayout.setVisibility(View.VISIBLE); |
- mManager.optOutPromoClicked(false); |
- updateMostVisitedPlaceholderVisibility(); |
- } |
- }); |
- mManager.optOutPromoShown(); |
- } |
- |
- private void updateSearchBoxOnScroll() { |
- if (mDisableUrlFocusChangeAnimations) return; |
- |
- float percentage = 0; |
- // During startup the view may not be fully initialized, so we only calculate the current |
- // percentage if some basic view properties are sane. |
- if (mScrollView.getHeight() != 0 && mSearchBoxView.getTop() != 0) { |
- int scrollY = mScrollView.getScrollY(); |
- percentage = Math.max( |
- 0f, Math.min(1f, scrollY / (float) mSearchBoxView.getTop())); |
- } |
- |
- updateVisualsForToolbarTransition(percentage); |
- |
- if (mSearchBoxScrollListener != null) { |
- mSearchBoxScrollListener.onScrollChanged(percentage); |
- } |
- } |
- |
- private void initializeSearchBoxScrollHandling() { |
- final Runnable mSnapScrollRunnable = new Runnable() { |
- @Override |
- public void run() { |
- if (!mPendingSnapScroll) return; |
- int scrollY = mScrollView.getScrollY(); |
- int dividerTop = mMostVisitedLayout.getTop() - mContentView.getPaddingTop(); |
- if (scrollY > 0 && scrollY < dividerTop) { |
- mScrollView.smoothScrollTo(0, scrollY < (dividerTop / 2) ? 0 : dividerTop); |
- } |
- mPendingSnapScroll = false; |
- } |
- }; |
- mScrollView.setOnScrollListener(new NewTabScrollView.OnScrollListener() { |
- @Override |
- public void onScrollChanged(int l, int t, int oldl, int oldt) { |
- if (mPendingSnapScroll) { |
- mScrollView.removeCallbacks(mSnapScrollRunnable); |
- mScrollView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_DELAY_MS); |
- } |
- updateSearchBoxOnScroll(); |
- } |
- }); |
- mScrollView.setOnTouchListener(new OnTouchListener() { |
- @Override |
- @SuppressLint("ClickableViewAccessibility") |
- public boolean onTouch(View v, MotionEvent event) { |
- if (mScrollView.getHandler() == null) return false; |
- mScrollView.removeCallbacks(mSnapScrollRunnable); |
- |
- if (event.getActionMasked() == MotionEvent.ACTION_CANCEL |
- || event.getActionMasked() == MotionEvent.ACTION_UP) { |
- mPendingSnapScroll = true; |
- mScrollView.postDelayed(mSnapScrollRunnable, SNAP_SCROLL_DELAY_MS); |
- } else { |
- mPendingSnapScroll = false; |
- } |
- return false; |
- } |
- }); |
- } |
- |
- /** |
- * Decrements the count of pending load tasks and notifies the manager when the page load |
- * is complete. |
- */ |
- private void loadTaskCompleted() { |
- assert mPendingLoadTasks > 0; |
- mPendingLoadTasks--; |
- if (mPendingLoadTasks == 0) { |
- if (mLoadHasCompleted) { |
- assert false; |
- } else { |
- mLoadHasCompleted = true; |
- mManager.onLoadingComplete(); |
- mMostVisitedDesign.onLoadingComplete(); |
- // Load the logo after everything else is finished, since it's lower priority. |
- loadSearchProviderLogo(); |
- } |
- } |
- } |
- |
- /** |
- * Loads the search provider logo (e.g. Google doodle), if any. |
- */ |
- private void loadSearchProviderLogo() { |
- mManager.getSearchProviderLogo(new LogoObserver() { |
- @Override |
- public void onLogoAvailable(Logo logo, boolean fromCache) { |
- if (logo == null && fromCache) return; |
- mSearchProviderLogoView.setMananger(mManager); |
- mSearchProviderLogoView.updateLogo(logo); |
- mSnapshotMostVisitedChanged = true; |
- } |
- }); |
- } |
- |
- /** |
- * Changes the layout depending on whether the selected search provider (e.g. Google, Bing) |
- * has a logo. |
- * @param hasLogo Whether the search provider has a logo. |
- */ |
- public void setSearchProviderHasLogo(boolean hasLogo) { |
- if (hasLogo == mSearchProviderHasLogo) return; |
- mSearchProviderHasLogo = hasLogo; |
- |
- mMostVisitedDesign.setSearchProviderHasLogo(mMostVisitedLayout, hasLogo); |
- |
- if (!hasLogo) setUrlFocusChangeAnimationPercentInternal(0); |
- |
- // Hide or show all the views above the Most Visited items. |
- int visibility = hasLogo ? View.VISIBLE : View.GONE; |
- int childCount = mContentView.getChildCount(); |
- for (int i = 0; i < childCount; i++) { |
- View child = mContentView.getChildAt(i); |
- if (child == mMostVisitedLayout) break; |
- // Don't change the visibility of a ViewStub as that will automagically inflate it. |
- if (child instanceof ViewStub) continue; |
- child.setVisibility(visibility); |
- } |
- |
- updateMostVisitedPlaceholderVisibility(); |
- |
- if (hasLogo) setUrlFocusChangeAnimationPercent(mUrlFocusChangePercent); |
- mSnapshotMostVisitedChanged = true; |
- } |
- |
- /** |
- * Updates whether the NewTabPage should animate on URL focus changes. |
- * @param disable Whether to disable the animations. |
- */ |
- void setUrlFocusAnimationsDisabled(boolean disable) { |
- if (disable == mDisableUrlFocusChangeAnimations) return; |
- mDisableUrlFocusChangeAnimations = disable; |
- if (!disable) setUrlFocusChangeAnimationPercent(mUrlFocusChangePercent); |
- } |
- |
- /** |
- * @return Whether URL focus animations are currently disabled. |
- */ |
- boolean urlFocusAnimationsDisabled() { |
- return mDisableUrlFocusChangeAnimations; |
- } |
- |
- /** |
- * Specifies the percentage the URL is focused during an animation. 1.0 specifies that the URL |
- * bar has focus and has completed the focus animation. 0 is when the URL bar is does not have |
- * any focus. |
- * |
- * @param percent The percentage of the URL bar focus animation. |
- */ |
- void setUrlFocusChangeAnimationPercent(float percent) { |
- mUrlFocusChangePercent = percent; |
- if (!mDisableUrlFocusChangeAnimations && mSearchProviderHasLogo) { |
- setUrlFocusChangeAnimationPercentInternal(percent); |
- } |
- } |
- |
- /** |
- * @return The percentage that the URL bar is focused during an animation. |
- */ |
- @VisibleForTesting |
- float getUrlFocusChangeAnimationPercent() { |
- return mUrlFocusChangePercent; |
- } |
- |
- /** |
- * Unconditionally sets the percentage the URL is focused during an animation, without updating |
- * mUrlFocusChangePercent. |
- * @see #setUrlFocusChangeAnimationPercent |
- */ |
- private void setUrlFocusChangeAnimationPercentInternal(float percent) { |
- mContentView.setTranslationY(percent * (-mMostVisitedLayout.getTop() |
- + mScrollView.getScrollY() + mContentView.getPaddingTop())); |
- updateVisualsForToolbarTransition(percent); |
- } |
- |
- private void updateVisualsForToolbarTransition(float transitionPercentage) { |
- // Complete the full alpha transition in the first 40% of the animation. |
- float searchUiAlpha = |
- transitionPercentage >= 0.4f ? 0f : (0.4f - transitionPercentage) * 2.5f; |
- // Ensure there are no rounding issues when the animation percent is 0. |
- if (transitionPercentage == 0f) searchUiAlpha = 1f; |
- |
- mSearchProviderLogoView.setAlpha(searchUiAlpha); |
- mSearchBoxView.setAlpha(searchUiAlpha); |
- } |
- |
- /** |
- * Get the bounds of the search box in relation to the top level NewTabPage view. |
- * |
- * @param originalBounds The bounding region of the search box without external transforms |
- * applied. The delta between this and the transformed bounds determines |
- * the amount of scroll applied to this view. |
- * @param transformedBounds The bounding region of the search box including any transforms |
- * applied by the parent view hierarchy up to the NewTabPage view. |
- * This more accurately reflects the current drawing location of the |
- * search box. |
- */ |
- void getSearchBoxBounds(Rect originalBounds, Rect transformedBounds) { |
- int searchBoxX = (int) mSearchBoxView.getX(); |
- int searchBoxY = (int) mSearchBoxView.getY(); |
- originalBounds.set( |
- searchBoxX + mSearchBoxView.getPaddingLeft(), |
- searchBoxY + mSearchBoxView.getPaddingTop(), |
- searchBoxX + mSearchBoxView.getWidth() - mSearchBoxView.getPaddingRight(), |
- searchBoxY + mSearchBoxView.getHeight() - mSearchBoxView.getPaddingBottom()); |
- |
- transformedBounds.set(originalBounds); |
- View view = (View) mSearchBoxView.getParent(); |
- while (view != null) { |
- transformedBounds.offset(-view.getScrollX(), -view.getScrollY()); |
- if (view == this) break; |
- transformedBounds.offset((int) view.getX(), (int) view.getY()); |
- view = (View) view.getParent(); |
- } |
- } |
- |
- /** |
- * Sets the listener for search box scroll changes. |
- * @param listener The listener to be notified on changes. |
- */ |
- void setSearchBoxScrollListener(OnSearchBoxScrollListener listener) { |
- mSearchBoxScrollListener = listener; |
- if (mSearchBoxScrollListener != null) updateSearchBoxOnScroll(); |
- } |
- |
- @Override |
- protected void onAttachedToWindow() { |
- super.onAttachedToWindow(); |
- assert mManager != null; |
- |
- if (mFirstShow) { |
- loadTaskCompleted(); |
- mFirstShow = false; |
- } else { |
- // Trigger a scroll update when reattaching the window to signal the toolbar that |
- // it needs to reset the NTP state. |
- if (mManager.isLocationBarShownInNTP()) updateSearchBoxOnScroll(); |
- } |
- } |
- |
- @Override |
- protected void onDetachedFromWindow() { |
- super.onDetachedFromWindow(); |
- setUrlFocusChangeAnimationPercent(0f); |
- } |
- |
- @Override |
- protected void onWindowVisibilityChanged(int visibility) { |
- super.onWindowVisibilityChanged(visibility); |
- |
- if (visibility == VISIBLE) { |
- mVoiceSearchButton.setVisibility( |
- FeatureUtilities.isRecognitionIntentPresent(getContext(), true) |
- ? VISIBLE : GONE); |
- } |
- } |
- |
- @Override |
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
- super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
- |
- // Make the search box and logo the same width as the most visited tiles. |
- if (mMostVisitedLayout.getVisibility() != GONE) { |
- int mostVisitedWidth = MeasureSpec.makeMeasureSpec(mMostVisitedLayout.getMeasuredWidth() |
- - mMostVisitedDesign.getMostVisitedLayoutBleed(), MeasureSpec.EXACTLY); |
- int searchBoxHeight = MeasureSpec.makeMeasureSpec( |
- mSearchBoxView.getMeasuredHeight(), MeasureSpec.EXACTLY); |
- int logoHeight = MeasureSpec.makeMeasureSpec( |
- mSearchProviderLogoView.getMeasuredHeight(), MeasureSpec.EXACTLY); |
- mSearchBoxView.measure(mostVisitedWidth, searchBoxHeight); |
- mSearchProviderLogoView.measure(mostVisitedWidth, logoHeight); |
- } |
- } |
- |
- /** |
- * @see org.chromium.chrome.browser.compositor.layouts.content. |
- * InvalidationAwareThumbnailProvider#shouldCaptureThumbnail() |
- */ |
- boolean shouldCaptureThumbnail() { |
- if (getWidth() == 0 || getHeight() == 0) return false; |
- |
- return mSnapshotMostVisitedChanged |
- || getWidth() != mSnapshotWidth |
- || getHeight() != mSnapshotHeight |
- || mScrollView.getScrollY() != mSnapshotScrollY; |
- } |
- |
- /** |
- * @see org.chromium.chrome.browser.compositor.layouts.content. |
- * InvalidationAwareThumbnailProvider#captureThumbnail(Canvas) |
- */ |
- void captureThumbnail(Canvas canvas) { |
- mSearchProviderLogoView.endAnimation(); |
- ViewUtils.captureBitmap(this, canvas); |
- mSnapshotWidth = getWidth(); |
- mSnapshotHeight = getHeight(); |
- mSnapshotScrollY = mScrollView.getScrollY(); |
- mSnapshotMostVisitedChanged = false; |
- } |
- |
- // OnLayoutChangeListener overrides |
- |
- @Override |
- public void onLayoutChange(View v, int left, int top, int right, int bottom, |
- int oldLeft, int oldTop, int oldRight, int oldBottom) { |
- int oldWidth = oldRight - oldLeft; |
- int newWidth = right - left; |
- if (oldWidth == newWidth) return; |
- |
- // Re-apply the url focus change amount after a rotation to ensure the views are correctly |
- // placed with their new layout configurations. |
- setUrlFocusChangeAnimationPercent(mUrlFocusChangePercent); |
- } |
- |
- // MostVisitedURLsObserver implementation |
- |
- @Override |
- public void onMostVisitedURLsAvailable(String[] titles, String[] urls) { |
- mMostVisitedLayout.removeAllViews(); |
- |
- MostVisitedItem[] oldItems = mMostVisitedItems; |
- int oldItemCount = oldItems == null ? 0 : oldItems.length; |
- mMostVisitedItems = new MostVisitedItem[titles.length]; |
- |
- final boolean isInitialLoad = !mHasReceivedMostVisitedSites; |
- LayoutInflater inflater = LayoutInflater.from(getContext()); |
- |
- // Add the most visited items to the page. |
- for (int i = 0; i < titles.length; i++) { |
- final String url = urls[i]; |
- final String title = titles[i]; |
- |
- // Look for an existing item to reuse. |
- MostVisitedItem item = null; |
- for (int j = 0; j < oldItemCount; j++) { |
- MostVisitedItem oldItem = oldItems[j]; |
- if (oldItem != null && TextUtils.equals(url, oldItem.getUrl()) |
- && TextUtils.equals(title, oldItem.getTitle())) { |
- item = oldItem; |
- item.setIndex(i); |
- oldItems[j] = null; |
- break; |
- } |
- } |
- |
- // If nothing can be reused, create a new item. |
- if (item == null) { |
- String displayTitle = getTitleForDisplay(title, url); |
- View view = mMostVisitedDesign.createMostVisitedItemView(inflater, url, title, |
- displayTitle, i, isInitialLoad); |
- item = new MostVisitedItem(mManager, title, url, i, view); |
- } |
- |
- mMostVisitedItems[i] = item; |
- mMostVisitedLayout.addView(item.getView()); |
- } |
- |
- mHasReceivedMostVisitedSites = true; |
- updateMostVisitedPlaceholderVisibility(); |
- |
- if (isInitialLoad) { |
- loadTaskCompleted(); |
- // The page contents are initially hidden; otherwise they'll be drawn centered on the |
- // page before the most visited sites are available and then jump upwards to make space |
- // once the most visited sites are available. |
- mContentView.setVisibility(View.VISIBLE); |
- } |
- mSnapshotMostVisitedChanged = true; |
- } |
- |
- /** |
- * Shows the most visited placeholder ("Nothing to see here") if there are no most visited |
- * items and there is no search provider logo. |
- */ |
- private void updateMostVisitedPlaceholderVisibility() { |
- boolean showPlaceholder = mHasReceivedMostVisitedSites |
- && !mManager.shouldShowOptOutPromo() |
- && mMostVisitedLayout.getChildCount() == 0 |
- && !mSearchProviderHasLogo; |
- |
- mNoSearchLogoSpacer.setVisibility( |
- (mSearchProviderHasLogo || showPlaceholder) ? View.GONE : View.INVISIBLE); |
- |
- if (showPlaceholder) { |
- if (mMostVisitedPlaceholder == null) { |
- ViewStub mostVisitedPlaceholderStub = (ViewStub) findViewById( |
- R.id.most_visited_placeholder_stub); |
- mMostVisitedPlaceholder = mostVisitedPlaceholderStub.inflate(); |
- } |
- mMostVisitedLayout.setVisibility(GONE); |
- mMostVisitedPlaceholder.setVisibility(VISIBLE); |
- return; |
- } else if (mMostVisitedPlaceholder != null) { |
- mMostVisitedLayout.setVisibility(VISIBLE); |
- mMostVisitedPlaceholder.setVisibility(GONE); |
- } |
- } |
- |
- /** |
- * Interface for creating the most visited layout and tiles. |
- * TODO(newt): delete this once a single design has been chosen. |
- */ |
- private interface MostVisitedDesign { |
- int getNumberOfTiles(boolean searchProviderHasLogo); |
- int getMostVisitedLayoutId(); |
- int getMostVisitedLayoutBleed(); |
- void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo); |
- View createMostVisitedItemView(LayoutInflater inflater, String url, String title, |
- String displayTitle, int index, boolean isInitialLoad); |
- void onLoadingComplete(); |
- } |
- |
- /** |
- * The old most visited design, where each tile shows a thumbnail of the page, a small favicon, |
- * and the title. |
- */ |
- private class ThumbnailMostVisitedDesign implements MostVisitedDesign { |
- |
- private static final int NUM_TILES = 6; |
- private static final int FAVICON_CORNER_RADIUS_DP = 2; |
- private static final int FAVICON_TEXT_SIZE_DP = 10; |
- private static final int FAVICON_BACKGROUND_COLOR = 0xff969696; |
- |
- private int mDesiredFaviconSize; |
- private RoundedIconGenerator mFaviconGenerator; |
- |
- ThumbnailMostVisitedDesign(Context context) { |
- Resources res = context.getResources(); |
- mDesiredFaviconSize = res.getDimensionPixelSize(R.dimen.most_visited_favicon_size); |
- int desiredFaviconSizeDp = Math.round( |
- mDesiredFaviconSize / res.getDisplayMetrics().density); |
- mFaviconGenerator = new RoundedIconGenerator( |
- context, desiredFaviconSizeDp, desiredFaviconSizeDp, FAVICON_CORNER_RADIUS_DP, |
- FAVICON_BACKGROUND_COLOR, FAVICON_TEXT_SIZE_DP); |
- } |
- |
- @Override |
- public int getNumberOfTiles(boolean searchProviderHasLogo) { |
- return NUM_TILES; |
- } |
- |
- @Override |
- public int getMostVisitedLayoutId() { |
- return R.layout.most_visited_layout; |
- } |
- |
- @Override |
- public int getMostVisitedLayoutBleed() { |
- return 0; |
- } |
- |
- @Override |
- public void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo) {} |
- |
- @Override |
- public View createMostVisitedItemView(LayoutInflater inflater, final String url, |
- String title, String displayTitle, int index, final boolean isInitialLoad) { |
- final MostVisitedItemView view = (MostVisitedItemView) inflater.inflate( |
- R.layout.most_visited_item, mMostVisitedLayout, false); |
- view.init(displayTitle); |
- |
- ThumbnailCallback thumbnailCallback = new ThumbnailCallback() { |
- @Override |
- public void onMostVisitedURLsThumbnailAvailable(Bitmap thumbnail) { |
- view.setThumbnail(thumbnail); |
- mSnapshotMostVisitedChanged = true; |
- if (isInitialLoad) loadTaskCompleted(); |
- } |
- }; |
- if (isInitialLoad) mPendingLoadTasks++; |
- mManager.getURLThumbnail(url, thumbnailCallback); |
- |
- FaviconImageCallback faviconCallback = new FaviconImageCallback() { |
- @Override |
- public void onFaviconAvailable(Bitmap image, String iconUrl) { |
- if (image == null) { |
- image = mFaviconGenerator.generateIconForUrl(url); |
- } |
- view.setFavicon(image); |
- mSnapshotMostVisitedChanged = true; |
- if (isInitialLoad) loadTaskCompleted(); |
- } |
- }; |
- if (isInitialLoad) mPendingLoadTasks++; |
- mManager.getLocalFaviconImageForURL(url, mDesiredFaviconSize, faviconCallback); |
- |
- return view; |
- } |
- |
- @Override |
- public void onLoadingComplete() {} |
- } |
- |
- /** |
- * The new-fangled design for most visited tiles, where each tile shows a large icon and title. |
- */ |
- private class IconMostVisitedDesign implements MostVisitedDesign { |
- |
- private static final int NUM_TILES = 8; |
- private static final int NUM_TILES_NO_LOGO = 12; |
- |
- private static final int ICON_CORNER_RADIUS_DP = 4; |
- private static final int ICON_TEXT_SIZE_DP = 20; |
- private static final int ICON_BACKGROUND_COLOR = 0xff787878; |
- private static final int ICON_MIN_SIZE_PX = 48; |
- |
- private int mMostVisitedLayoutBleed; |
- private int mMinIconSize; |
- private int mDesiredIconSize; |
- private RoundedIconGenerator mIconGenerator; |
- |
- private int mNumGrayIcons; |
- private int mNumColorIcons; |
- private int mNumRealIcons; |
- |
- IconMostVisitedDesign(Context context) { |
- Resources res = context.getResources(); |
- mMostVisitedLayoutBleed = res.getDimensionPixelSize( |
- R.dimen.icon_most_visited_layout_bleed); |
- mDesiredIconSize = res.getDimensionPixelSize(R.dimen.icon_most_visited_icon_size); |
- // On ldpi devices, mDesiredIconSize could be even smaller than ICON_MIN_SIZE_PX. |
- mMinIconSize = Math.min(mDesiredIconSize, ICON_MIN_SIZE_PX); |
- int desiredIconSizeDp = Math.round( |
- mDesiredIconSize / res.getDisplayMetrics().density); |
- mIconGenerator = new RoundedIconGenerator( |
- context, desiredIconSizeDp, desiredIconSizeDp, ICON_CORNER_RADIUS_DP, |
- ICON_BACKGROUND_COLOR, ICON_TEXT_SIZE_DP); |
- } |
- |
- @Override |
- public int getNumberOfTiles(boolean searchProviderHasLogo) { |
- return searchProviderHasLogo ? NUM_TILES : NUM_TILES_NO_LOGO; |
- } |
- |
- @Override |
- public int getMostVisitedLayoutId() { |
- return R.layout.icon_most_visited_layout; |
- } |
- |
- @Override |
- public int getMostVisitedLayoutBleed() { |
- return mMostVisitedLayoutBleed; |
- } |
- |
- @Override |
- public void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo) { |
- int paddingTop = getResources().getDimensionPixelSize(hasLogo |
- ? R.dimen.icon_most_visited_layout_padding_top |
- : R.dimen.icon_most_visited_layout_no_logo_padding_top); |
- mostVisitedLayout.setPadding(0, paddingTop, 0, 0); |
- } |
- |
- @Override |
- public View createMostVisitedItemView(LayoutInflater inflater, final String url, |
- String title, String displayTitle, int index, final boolean isInitialLoad) { |
- final IconMostVisitedItemView view = (IconMostVisitedItemView) inflater.inflate( |
- R.layout.icon_most_visited_item, mMostVisitedLayout, false); |
- view.setTitle(displayTitle); |
- |
- LargeIconCallback iconCallback = new LargeIconCallback() { |
- @Override |
- public void onLargeIconAvailable(Bitmap icon, int fallbackColor) { |
- if (icon == null) { |
- mIconGenerator.setBackgroundColor(fallbackColor); |
- icon = mIconGenerator.generateIconForUrl(url); |
- view.setIcon(new BitmapDrawable(getResources(), icon)); |
- if (isInitialLoad) { |
- if (fallbackColor == ICON_BACKGROUND_COLOR) { |
- mNumGrayIcons++; |
- } else { |
- mNumColorIcons++; |
- } |
- } |
- } else { |
- RoundedBitmapDrawable roundedIcon = RoundedBitmapDrawableFactory.create( |
- getResources(), icon); |
- int cornerRadius = Math.round(ICON_CORNER_RADIUS_DP |
- * getResources().getDisplayMetrics().density * icon.getWidth() |
- / mDesiredIconSize); |
- roundedIcon.setCornerRadius(cornerRadius); |
- roundedIcon.setAntiAlias(true); |
- roundedIcon.setFilterBitmap(true); |
- view.setIcon(roundedIcon); |
- if (isInitialLoad) mNumRealIcons++; |
- } |
- mSnapshotMostVisitedChanged = true; |
- if (isInitialLoad) loadTaskCompleted(); |
- } |
- }; |
- if (isInitialLoad) mPendingLoadTasks++; |
- mManager.getLargeIconForUrl(url, mMinIconSize, iconCallback); |
- |
- return view; |
- } |
- |
- @Override |
- public void onLoadingComplete() { |
- RecordHistogram.recordCount100Histogram("NewTabPage.IconsGray", mNumGrayIcons); |
- RecordHistogram.recordCount100Histogram("NewTabPage.IconsColor", mNumColorIcons); |
- RecordHistogram.recordCount100Histogram("NewTabPage.IconsReal", mNumRealIcons); |
- } |
- } |
-} |