// 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.preferences.website; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.preference.Preference; import android.text.format.Formatter; import android.view.View; import android.widget.TextView; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.chrome.R; import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.widget.RoundedIconGenerator; /** * A preference that displays a website's favicon and URL and, optionally, the amount of local * storage used by the site. */ @SuppressFBWarnings("EQ_COMPARETO_USE_OBJECT_EQUALS") class WebsitePreference extends Preference implements FaviconImageCallback { private final Website mSite; private final SiteSettingsCategory mCategory; private static final int TEXT_SIZE_SP = 13; // Loads the favicons asynchronously. private FaviconHelper mFaviconHelper; // Whether the favicon has been fetched already. private boolean mFaviconFetched = false; // Metrics for favicon processing. private static final int FAVICON_CORNER_RADIUS_DP = 2; private static final int FAVICON_PADDING_DP = 4; private static final int FAVICON_TEXT_SIZE_DP = 10; private static final int FAVICON_BACKGROUND_COLOR = 0xff969696; private int mFaviconSizePx; WebsitePreference(Context context, Website site, SiteSettingsCategory category) { super(context); mSite = site; mCategory = category; setWidgetLayoutResource(R.layout.website_features); mFaviconSizePx = context.getResources().getDimensionPixelSize(R.dimen.default_favicon_size); // To make sure the layout stays stable throughout, we assign a // transparent drawable as the icon initially. This is so that // we can fetch the favicon in the background and not have to worry // about the title appearing to jump (http://crbug.com/453626) when the // favicon becomes available. setIcon(new ColorDrawable(Color.TRANSPARENT)); refresh(); } public void putSiteIntoExtras(String key) { getExtras().putSerializable(key, mSite); } /** * Return the Website this object is representing. */ public Website site() { return mSite; } @Override public void onFaviconAvailable(Bitmap image, String iconUrl) { mFaviconHelper.destroy(); mFaviconHelper = null; if (image == null) { // Invalid favicon, produce a generic one. float density = getContext().getResources().getDisplayMetrics().density; int faviconSizeDp = Math.round(mFaviconSizePx / density); RoundedIconGenerator faviconGenerator = new RoundedIconGenerator( getContext(), faviconSizeDp, faviconSizeDp, FAVICON_CORNER_RADIUS_DP, FAVICON_BACKGROUND_COLOR, FAVICON_TEXT_SIZE_DP); image = faviconGenerator.generateIconForUrl(faviconUrl()); } setIcon(new BitmapDrawable(getContext().getResources(), image)); } /** * Returns the url of the site to fetch a favicon for. */ private String faviconUrl() { String origin = mSite.getAddress().getOrigin(); if (origin == null) { return "http://" + mSite.getAddress().getHost(); } Uri uri = Uri.parse(origin); if (uri.getPort() != -1) { // Remove the port. uri = uri.buildUpon().authority(uri.getHost()).build(); } return uri.toString(); } private void refresh() { setTitle(mSite.getTitle()); String subtitleText = mSite.getSummary(); if (subtitleText != null) { setSummary(String.format(getContext().getString(R.string.website_settings_embedded_in), subtitleText)); } } @Override public int compareTo(Preference preference) { if (!(preference instanceof WebsitePreference)) { return super.compareTo(preference); } WebsitePreference other = (WebsitePreference) preference; if (mCategory.showStorageSites()) { return mSite.compareByStorageTo(other.mSite); } return mSite.compareByAddressTo(other.mSite); } @Override protected void onBindView(View view) { super.onBindView(view); TextView usageText = (TextView) view.findViewById(R.id.usage_text); usageText.setVisibility(View.GONE); if (mCategory.showStorageSites()) { long totalUsage = mSite.getTotalUsage(); if (totalUsage > 0) { usageText.setText(Formatter.formatShortFileSize(getContext(), totalUsage)); usageText.setTextSize(TEXT_SIZE_SP); usageText.setVisibility(View.VISIBLE); } } if (!mFaviconFetched) { // Start the favicon fetching. Will respond in onFaviconAvailable. mFaviconHelper = new FaviconHelper(); if (!mFaviconHelper.getLocalFaviconImageForURL( Profile.getLastUsedProfile(), faviconUrl(), mFaviconSizePx, this)) { onFaviconAvailable(null, null); } mFaviconFetched = true; } float density = getContext().getResources().getDisplayMetrics().density; int iconPadding = Math.round(FAVICON_PADDING_DP * density); View iconView = view.findViewById(android.R.id.icon); iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); } }