mobile/android/base/home/TopSitesGridItemView.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.home;
michael@0 7
michael@0 8 import org.mozilla.gecko.favicons.Favicons;
michael@0 9 import org.mozilla.gecko.R;
michael@0 10
michael@0 11 import android.content.Context;
michael@0 12 import android.graphics.Bitmap;
michael@0 13 import android.text.TextUtils;
michael@0 14 import android.util.AttributeSet;
michael@0 15 import android.view.LayoutInflater;
michael@0 16 import android.widget.ImageView;
michael@0 17 import android.widget.ImageView.ScaleType;
michael@0 18 import android.widget.RelativeLayout;
michael@0 19 import android.widget.TextView;
michael@0 20
michael@0 21 /**
michael@0 22 * A view that displays the thumbnail and the title/url for a top/pinned site.
michael@0 23 * If the title/url is longer than the width of the view, they are faded out.
michael@0 24 * If there is no valid url, a default string is shown at 50% opacity.
michael@0 25 * This is denoted by the empty state.
michael@0 26 */
michael@0 27 public class TopSitesGridItemView extends RelativeLayout {
michael@0 28 private static final String LOGTAG = "GeckoTopSitesGridItemView";
michael@0 29
michael@0 30 // Empty state, to denote there is no valid url.
michael@0 31 private static final int[] STATE_EMPTY = { android.R.attr.state_empty };
michael@0 32
michael@0 33 private static final ScaleType SCALE_TYPE_FAVICON = ScaleType.CENTER;
michael@0 34 private static final ScaleType SCALE_TYPE_RESOURCE = ScaleType.CENTER;
michael@0 35 private static final ScaleType SCALE_TYPE_THUMBNAIL = ScaleType.CENTER_CROP;
michael@0 36
michael@0 37 // Child views.
michael@0 38 private final TextView mTitleView;
michael@0 39 private final ImageView mThumbnailView;
michael@0 40
michael@0 41 // Data backing this view.
michael@0 42 private String mTitle;
michael@0 43 private String mUrl;
michael@0 44 private String mFaviconURL;
michael@0 45
michael@0 46 private boolean mThumbnailSet;
michael@0 47
michael@0 48 // Pinned state.
michael@0 49 private boolean mIsPinned = false;
michael@0 50
michael@0 51 // Dirty state.
michael@0 52 private boolean mIsDirty = false;
michael@0 53
michael@0 54 // Empty state.
michael@0 55 private boolean mIsEmpty = true;
michael@0 56 private int mLoadId = Favicons.NOT_LOADING;
michael@0 57
michael@0 58 public TopSitesGridItemView(Context context) {
michael@0 59 this(context, null);
michael@0 60 }
michael@0 61
michael@0 62 public TopSitesGridItemView(Context context, AttributeSet attrs) {
michael@0 63 this(context, attrs, R.attr.topSitesGridItemViewStyle);
michael@0 64 }
michael@0 65
michael@0 66 public TopSitesGridItemView(Context context, AttributeSet attrs, int defStyle) {
michael@0 67 super(context, attrs, defStyle);
michael@0 68
michael@0 69 LayoutInflater.from(context).inflate(R.layout.top_sites_grid_item_view, this);
michael@0 70
michael@0 71 mTitleView = (TextView) findViewById(R.id.title);
michael@0 72 mThumbnailView = (ImageView) findViewById(R.id.thumbnail);
michael@0 73 }
michael@0 74
michael@0 75 /**
michael@0 76 * {@inheritDoc}
michael@0 77 */
michael@0 78 @Override
michael@0 79 public int[] onCreateDrawableState(int extraSpace) {
michael@0 80 final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
michael@0 81
michael@0 82 if (mIsEmpty) {
michael@0 83 mergeDrawableStates(drawableState, STATE_EMPTY);
michael@0 84 }
michael@0 85
michael@0 86 return drawableState;
michael@0 87 }
michael@0 88
michael@0 89 /**
michael@0 90 * @return The title shown by this view.
michael@0 91 */
michael@0 92 public String getTitle() {
michael@0 93 return (!TextUtils.isEmpty(mTitle) ? mTitle : mUrl);
michael@0 94 }
michael@0 95
michael@0 96 /**
michael@0 97 * @return The url shown by this view.
michael@0 98 */
michael@0 99 public String getUrl() {
michael@0 100 return mUrl;
michael@0 101 }
michael@0 102
michael@0 103 /**
michael@0 104 * @return true, if this view is pinned, false otherwise.
michael@0 105 */
michael@0 106 public boolean isPinned() {
michael@0 107 return mIsPinned;
michael@0 108 }
michael@0 109
michael@0 110 /**
michael@0 111 * @return true, if this view has no content to show.
michael@0 112 */
michael@0 113 public boolean isEmpty() {
michael@0 114 return mIsEmpty;
michael@0 115 }
michael@0 116
michael@0 117 /**
michael@0 118 * @param title The title for this view.
michael@0 119 */
michael@0 120 public void setTitle(String title) {
michael@0 121 if (mTitle != null && mTitle.equals(title)) {
michael@0 122 return;
michael@0 123 }
michael@0 124
michael@0 125 mTitle = title;
michael@0 126 updateTitleView();
michael@0 127 }
michael@0 128
michael@0 129 /**
michael@0 130 * @param url The url for this view.
michael@0 131 */
michael@0 132 public void setUrl(String url) {
michael@0 133 if (mUrl != null && mUrl.equals(url)) {
michael@0 134 return;
michael@0 135 }
michael@0 136
michael@0 137 mUrl = url;
michael@0 138 updateTitleView();
michael@0 139 }
michael@0 140
michael@0 141 /**
michael@0 142 * @param pinned The pinned state of this view.
michael@0 143 */
michael@0 144 public void setPinned(boolean pinned) {
michael@0 145 mIsPinned = pinned;
michael@0 146 mTitleView.setCompoundDrawablesWithIntrinsicBounds(pinned ? R.drawable.pin : 0, 0, 0, 0);
michael@0 147 }
michael@0 148
michael@0 149 public void blankOut() {
michael@0 150 mUrl = "";
michael@0 151 mTitle = "";
michael@0 152 mIsPinned = false;
michael@0 153 updateTitleView();
michael@0 154 mTitleView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
michael@0 155 setLoadId(Favicons.NOT_LOADING);
michael@0 156 displayThumbnail(R.drawable.top_site_add);
michael@0 157 }
michael@0 158
michael@0 159 public void markAsDirty() {
michael@0 160 mIsDirty = true;
michael@0 161 }
michael@0 162
michael@0 163 /**
michael@0 164 * Updates the title, URL, and pinned state of this view.
michael@0 165 *
michael@0 166 * Also resets our loadId to NOT_LOADING.
michael@0 167 *
michael@0 168 * Returns true if any fields changed.
michael@0 169 */
michael@0 170 public boolean updateState(final String title, final String url, final boolean pinned, final Bitmap thumbnail) {
michael@0 171 boolean changed = false;
michael@0 172 if (mUrl == null || !mUrl.equals(url)) {
michael@0 173 mUrl = url;
michael@0 174 changed = true;
michael@0 175 }
michael@0 176
michael@0 177 if (mTitle == null || !mTitle.equals(title)) {
michael@0 178 mTitle = title;
michael@0 179 changed = true;
michael@0 180 }
michael@0 181
michael@0 182 if (thumbnail != null) {
michael@0 183 displayThumbnail(thumbnail);
michael@0 184 } else if (changed) {
michael@0 185 // Because we'll have a new favicon or thumbnail arriving shortly, and
michael@0 186 // we need to not reject it because we already had a thumbnail.
michael@0 187 mThumbnailSet = false;
michael@0 188 }
michael@0 189
michael@0 190 if (changed) {
michael@0 191 updateTitleView();
michael@0 192 setLoadId(Favicons.NOT_LOADING);
michael@0 193 }
michael@0 194
michael@0 195 if (mIsPinned != pinned) {
michael@0 196 mIsPinned = pinned;
michael@0 197 mTitleView.setCompoundDrawablesWithIntrinsicBounds(pinned ? R.drawable.pin : 0, 0, 0, 0);
michael@0 198 changed = true;
michael@0 199 }
michael@0 200
michael@0 201 // The dirty state forces the state update to return true
michael@0 202 // so that the adapter loads favicons once the thumbnails
michael@0 203 // are loaded in TopSitesPanel/TopSitesGridAdapter.
michael@0 204 changed = (changed || mIsDirty);
michael@0 205 mIsDirty = false;
michael@0 206
michael@0 207 return changed;
michael@0 208 }
michael@0 209
michael@0 210 /**
michael@0 211 * Display the thumbnail from a resource.
michael@0 212 *
michael@0 213 * @param resId Resource ID of the drawable to show.
michael@0 214 */
michael@0 215 public void displayThumbnail(int resId) {
michael@0 216 mThumbnailView.setScaleType(SCALE_TYPE_RESOURCE);
michael@0 217 mThumbnailView.setImageResource(resId);
michael@0 218 mThumbnailView.setBackgroundColor(0x0);
michael@0 219 mThumbnailSet = false;
michael@0 220 }
michael@0 221
michael@0 222 /**
michael@0 223 * Display the thumbnail from a bitmap.
michael@0 224 *
michael@0 225 * @param thumbnail The bitmap to show as thumbnail.
michael@0 226 */
michael@0 227 public void displayThumbnail(Bitmap thumbnail) {
michael@0 228 if (thumbnail == null) {
michael@0 229 // Show a favicon based view instead.
michael@0 230 displayThumbnail(R.drawable.favicon);
michael@0 231 return;
michael@0 232 }
michael@0 233 mThumbnailSet = true;
michael@0 234 Favicons.cancelFaviconLoad(mLoadId);
michael@0 235
michael@0 236 mThumbnailView.setScaleType(SCALE_TYPE_THUMBNAIL);
michael@0 237 mThumbnailView.setImageBitmap(thumbnail);
michael@0 238 mThumbnailView.setBackgroundDrawable(null);
michael@0 239 }
michael@0 240
michael@0 241 public void displayFavicon(Bitmap favicon, String faviconURL, int expectedLoadId) {
michael@0 242 if (mLoadId != Favicons.NOT_LOADING &&
michael@0 243 mLoadId != expectedLoadId) {
michael@0 244 // View recycled.
michael@0 245 return;
michael@0 246 }
michael@0 247
michael@0 248 // Yes, there's a chance of a race here.
michael@0 249 displayFavicon(favicon, faviconURL);
michael@0 250 }
michael@0 251
michael@0 252 /**
michael@0 253 * Display the thumbnail from a favicon.
michael@0 254 *
michael@0 255 * @param favicon The favicon to show as thumbnail.
michael@0 256 */
michael@0 257 public void displayFavicon(Bitmap favicon, String faviconURL) {
michael@0 258 if (mThumbnailSet) {
michael@0 259 // Already showing a thumbnail; do nothing.
michael@0 260 return;
michael@0 261 }
michael@0 262
michael@0 263 if (favicon == null) {
michael@0 264 // Should show default favicon.
michael@0 265 displayThumbnail(R.drawable.favicon);
michael@0 266 return;
michael@0 267 }
michael@0 268
michael@0 269 if (faviconURL != null) {
michael@0 270 mFaviconURL = faviconURL;
michael@0 271 }
michael@0 272
michael@0 273 mThumbnailView.setScaleType(SCALE_TYPE_FAVICON);
michael@0 274 mThumbnailView.setImageBitmap(favicon);
michael@0 275
michael@0 276 if (mFaviconURL != null) {
michael@0 277 mThumbnailView.setBackgroundColor(Favicons.getFaviconColor(mFaviconURL));
michael@0 278 }
michael@0 279 }
michael@0 280
michael@0 281 /**
michael@0 282 * Update the title shown by this view. If both title and url
michael@0 283 * are empty, mark the state as STATE_EMPTY and show a default text.
michael@0 284 */
michael@0 285 private void updateTitleView() {
michael@0 286 String title = getTitle();
michael@0 287 if (!TextUtils.isEmpty(title)) {
michael@0 288 mTitleView.setText(title);
michael@0 289 mIsEmpty = false;
michael@0 290 } else {
michael@0 291 mTitleView.setText(R.string.home_top_sites_add);
michael@0 292 mIsEmpty = true;
michael@0 293 }
michael@0 294
michael@0 295 // Refresh for state change.
michael@0 296 refreshDrawableState();
michael@0 297 }
michael@0 298
michael@0 299 public void setLoadId(int aLoadId) {
michael@0 300 Favicons.cancelFaviconLoad(mLoadId);
michael@0 301 mLoadId = aLoadId;
michael@0 302 }
michael@0 303 }

mercurial