summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java312
1 files changed, 312 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java b/mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java
new file mode 100644
index 000000000..c17aff209
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/home/TopSitesGridItemView.java
@@ -0,0 +1,312 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.home;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.ImageView.ScaleType;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserContract.TopSites;
+import org.mozilla.gecko.icons.IconCallback;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.icons.Icons;
+
+import java.util.concurrent.Future;
+
+/**
+ * A view that displays the thumbnail and the title/url for a top/pinned site.
+ * If the title/url is longer than the width of the view, they are faded out.
+ * If there is no valid url, a default string is shown at 50% opacity.
+ * This is denoted by the empty state.
+ */
+public class TopSitesGridItemView extends RelativeLayout implements IconCallback {
+ private static final String LOGTAG = "GeckoTopSitesGridItemView";
+
+ // Empty state, to denote there is no valid url.
+ private static final int[] STATE_EMPTY = { android.R.attr.state_empty };
+
+ private static final ScaleType SCALE_TYPE_FAVICON = ScaleType.CENTER;
+ private static final ScaleType SCALE_TYPE_RESOURCE = ScaleType.CENTER;
+ private static final ScaleType SCALE_TYPE_THUMBNAIL = ScaleType.CENTER_CROP;
+ private static final ScaleType SCALE_TYPE_URL = ScaleType.CENTER_INSIDE;
+
+ // Child views.
+ private final TextView mTitleView;
+ private final TopSitesThumbnailView mThumbnailView;
+
+ // Data backing this view.
+ private String mTitle;
+ private String mUrl;
+
+ private boolean mThumbnailSet;
+
+ // Matches BrowserContract.TopSites row types
+ private int mType = -1;
+
+ // Dirty state.
+ private boolean mIsDirty;
+
+ private Future<IconResponse> mOngoingIconRequest;
+
+ public TopSitesGridItemView(Context context) {
+ this(context, null);
+ }
+
+ public TopSitesGridItemView(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.topSitesGridItemViewStyle);
+ }
+
+ public TopSitesGridItemView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ LayoutInflater.from(context).inflate(R.layout.top_sites_grid_item_view, this);
+
+ mTitleView = (TextView) findViewById(R.id.title);
+ mThumbnailView = (TopSitesThumbnailView) findViewById(R.id.thumbnail);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+
+ if (mType == TopSites.TYPE_BLANK) {
+ mergeDrawableStates(drawableState, STATE_EMPTY);
+ }
+
+ return drawableState;
+ }
+
+ /**
+ * @return The title shown by this view.
+ */
+ public String getTitle() {
+ return (!TextUtils.isEmpty(mTitle) ? mTitle : mUrl);
+ }
+
+ /**
+ * @return The url shown by this view.
+ */
+ public String getUrl() {
+ return mUrl;
+ }
+
+ /**
+ * @return The site type associated with this view.
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * @param title The title for this view.
+ */
+ public void setTitle(String title) {
+ if (mTitle != null && mTitle.equals(title)) {
+ return;
+ }
+
+ mTitle = title;
+ updateTitleView();
+ }
+
+ /**
+ * @param url The url for this view.
+ */
+ public void setUrl(String url) {
+ if (mUrl != null && mUrl.equals(url)) {
+ return;
+ }
+
+ mUrl = url;
+ updateTitleView();
+ }
+
+ public void blankOut() {
+ mUrl = "";
+ mTitle = "";
+ updateType(TopSites.TYPE_BLANK);
+ updateTitleView();
+ cancelIconLoading();
+ ImageLoader.with(getContext()).cancelRequest(mThumbnailView);
+ displayThumbnail(R.drawable.top_site_add);
+
+ }
+
+ public void markAsDirty() {
+ mIsDirty = true;
+ }
+
+ /**
+ * Updates the title, URL, and pinned state of this view.
+ *
+ * Also resets our loadId to NOT_LOADING.
+ *
+ * Returns true if any fields changed.
+ */
+ public boolean updateState(final String title, final String url, final int type, final TopSitesPanel.ThumbnailInfo thumbnail) {
+ boolean changed = false;
+ if (mUrl == null || !mUrl.equals(url)) {
+ mUrl = url;
+ changed = true;
+ }
+
+ if (mTitle == null || !mTitle.equals(title)) {
+ mTitle = title;
+ changed = true;
+ }
+
+ if (thumbnail != null) {
+ if (thumbnail.imageUrl != null) {
+ displayThumbnail(thumbnail.imageUrl, thumbnail.bgColor);
+ } else if (thumbnail.bitmap != null) {
+ displayThumbnail(thumbnail.bitmap);
+ }
+ } else if (changed) {
+ // Because we'll have a new favicon or thumbnail arriving shortly, and
+ // we need to not reject it because we already had a thumbnail.
+ mThumbnailSet = false;
+ }
+
+ if (changed) {
+ updateTitleView();
+ cancelIconLoading();
+ ImageLoader.with(getContext()).cancelRequest(mThumbnailView);
+ }
+
+ if (updateType(type)) {
+ changed = true;
+ }
+
+ // The dirty state forces the state update to return true
+ // so that the adapter loads favicons once the thumbnails
+ // are loaded in TopSitesPanel/TopSitesGridAdapter.
+ changed = (changed || mIsDirty);
+ mIsDirty = false;
+
+ return changed;
+ }
+
+ /**
+ * Try to load an icon for the given page URL.
+ */
+ public void loadFavicon(String pageUrl) {
+ mOngoingIconRequest = Icons.with(getContext())
+ .pageUrl(pageUrl)
+ .skipNetwork()
+ .build()
+ .execute(this);
+ }
+
+ private void cancelIconLoading() {
+ if (mOngoingIconRequest != null) {
+ mOngoingIconRequest.cancel(true);
+ }
+ }
+
+ /**
+ * Display the thumbnail from a resource.
+ *
+ * @param resId Resource ID of the drawable to show.
+ */
+ public void displayThumbnail(int resId) {
+ mThumbnailView.setScaleType(SCALE_TYPE_RESOURCE);
+ mThumbnailView.setImageResource(resId);
+ mThumbnailView.setBackgroundColor(0x0);
+ mThumbnailSet = false;
+ }
+
+ /**
+ * Display the thumbnail from a bitmap.
+ *
+ * @param thumbnail The bitmap to show as thumbnail.
+ */
+ public void displayThumbnail(Bitmap thumbnail) {
+ if (thumbnail == null) {
+ return;
+ }
+
+ mThumbnailSet = true;
+
+ cancelIconLoading();
+ ImageLoader.with(getContext()).cancelRequest(mThumbnailView);
+
+ mThumbnailView.setScaleType(SCALE_TYPE_THUMBNAIL);
+ mThumbnailView.setImageBitmap(thumbnail, true);
+ mThumbnailView.setBackgroundDrawable(null);
+ }
+
+ /**
+ * Display the thumbnail from a URL.
+ *
+ * @param imageUrl URL of the image to show.
+ * @param bgColor background color to use in the view.
+ */
+ public void displayThumbnail(final String imageUrl, final int bgColor) {
+ mThumbnailView.setScaleType(SCALE_TYPE_URL);
+ mThumbnailView.setBackgroundColor(bgColor);
+ mThumbnailSet = true;
+
+ ImageLoader.with(getContext())
+ .load(imageUrl)
+ .noFade()
+ .into(mThumbnailView);
+ }
+
+ /**
+ * Update the item type associated with this view. Returns true if
+ * the type has changed, false otherwise.
+ */
+ private boolean updateType(int type) {
+ if (mType == type) {
+ return false;
+ }
+
+ mType = type;
+ refreshDrawableState();
+
+ int pinResourceId = (type == TopSites.TYPE_PINNED ? R.drawable.pin : 0);
+ mTitleView.setCompoundDrawablesWithIntrinsicBounds(pinResourceId, 0, 0, 0);
+
+ return true;
+ }
+
+ /**
+ * Update the title shown by this view. If both title and url
+ * are empty, mark the state as STATE_EMPTY and show a default text.
+ */
+ private void updateTitleView() {
+ String title = getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ mTitleView.setText(title);
+ } else {
+ mTitleView.setText(R.string.home_top_sites_add);
+ }
+ }
+
+ /**
+ * Display the loaded icon (if no thumbnail is set).
+ */
+ @Override
+ public void onIconResponse(IconResponse response) {
+ if (mThumbnailSet) {
+ // Already showing a thumbnail; do nothing.
+ return;
+ }
+
+ mThumbnailView.setScaleType(SCALE_TYPE_FAVICON);
+ mThumbnailView.setImageBitmap(response.getBitmap(), false);
+ mThumbnailView.setBackgroundColorWithOpacityFilter(response.getColor());
+ }
+}