mobile/android/base/widget/FaviconView.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 file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.widget;
michael@0 7
michael@0 8 import org.mozilla.gecko.R;
michael@0 9 import org.mozilla.gecko.favicons.Favicons;
michael@0 10
michael@0 11 import android.content.Context;
michael@0 12 import android.graphics.Bitmap;
michael@0 13 import android.graphics.Canvas;
michael@0 14 import android.graphics.Paint;
michael@0 15 import android.graphics.RectF;
michael@0 16 import android.util.AttributeSet;
michael@0 17 import android.widget.ImageView;
michael@0 18 /**
michael@0 19 * Special version of ImageView for favicons.
michael@0 20 * Displays solid colour background around Favicon to fill space not occupied by the icon. Colour
michael@0 21 * selected is the dominant colour of the provided Favicon.
michael@0 22 */
michael@0 23 public class FaviconView extends ImageView {
michael@0 24 private Bitmap mIconBitmap;
michael@0 25
michael@0 26 // Reference to the unscaled bitmap, if any, to prevent repeated assignments of the same bitmap
michael@0 27 // to the view from causing repeated rescalings (Some of the callers do this)
michael@0 28 private Bitmap mUnscaledBitmap;
michael@0 29
michael@0 30 // Key into the Favicon dominant colour cache. Should be the Favicon URL if the image displayed
michael@0 31 // here is a Favicon managed by the caching system. If not, any appropriately unique-to-this-image
michael@0 32 // string is acceptable.
michael@0 33 private String mIconKey;
michael@0 34
michael@0 35 private int mActualWidth;
michael@0 36 private int mActualHeight;
michael@0 37
michael@0 38 // Flag indicating if the most recently assigned image is considered likely to need scaling.
michael@0 39 private boolean mScalingExpected;
michael@0 40
michael@0 41 // Dominant color of the favicon.
michael@0 42 private int mDominantColor;
michael@0 43
michael@0 44 // Stroke width for the border.
michael@0 45 private static float sStrokeWidth;
michael@0 46
michael@0 47 // Paint for drawing the stroke.
michael@0 48 private static Paint sStrokePaint;
michael@0 49
michael@0 50 // Paint for drawing the background.
michael@0 51 private static Paint sBackgroundPaint;
michael@0 52
michael@0 53 // Size of the stroke rectangle.
michael@0 54 private final RectF mStrokeRect;
michael@0 55
michael@0 56 // Size of the background rectangle.
michael@0 57 private final RectF mBackgroundRect;
michael@0 58
michael@0 59 // Initializing the static paints.
michael@0 60 static {
michael@0 61 sStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
michael@0 62 sStrokePaint.setStyle(Paint.Style.STROKE);
michael@0 63
michael@0 64 sBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
michael@0 65 sBackgroundPaint.setStyle(Paint.Style.FILL);
michael@0 66 }
michael@0 67
michael@0 68 public FaviconView(Context context, AttributeSet attrs) {
michael@0 69 super(context, attrs);
michael@0 70 setScaleType(ImageView.ScaleType.CENTER);
michael@0 71
michael@0 72 mStrokeRect = new RectF();
michael@0 73 mBackgroundRect = new RectF();
michael@0 74
michael@0 75 if (sStrokeWidth == 0) {
michael@0 76 sStrokeWidth = getResources().getDisplayMetrics().density;
michael@0 77 sStrokePaint.setStrokeWidth(sStrokeWidth);
michael@0 78 }
michael@0 79
michael@0 80 mStrokeRect.left = mStrokeRect.top = sStrokeWidth;
michael@0 81 mBackgroundRect.left = mBackgroundRect.top = sStrokeWidth * 2.0f;
michael@0 82 }
michael@0 83
michael@0 84 @Override
michael@0 85 protected void onSizeChanged(int w, int h, int oldw, int oldh){
michael@0 86 super.onSizeChanged(w, h, oldw, oldh);
michael@0 87
michael@0 88 // No point rechecking the image if there hasn't really been any change.
michael@0 89 if (w == mActualWidth && h == mActualHeight) {
michael@0 90 return;
michael@0 91 }
michael@0 92
michael@0 93 mActualWidth = w;
michael@0 94 mActualHeight = h;
michael@0 95
michael@0 96 mStrokeRect.right = w - sStrokeWidth;
michael@0 97 mStrokeRect.bottom = h - sStrokeWidth;
michael@0 98 mBackgroundRect.right = mStrokeRect.right - sStrokeWidth;
michael@0 99 mBackgroundRect.bottom = mStrokeRect.bottom - sStrokeWidth;
michael@0 100
michael@0 101 formatImage();
michael@0 102 }
michael@0 103
michael@0 104 @Override
michael@0 105 public void onDraw(Canvas canvas) {
michael@0 106 super.onDraw(canvas);
michael@0 107
michael@0 108 // 27.5% transparent dominant color.
michael@0 109 sBackgroundPaint.setColor(mDominantColor & 0x46FFFFFF);
michael@0 110 canvas.drawRect(mStrokeRect, sBackgroundPaint);
michael@0 111
michael@0 112 sStrokePaint.setColor(mDominantColor);
michael@0 113 canvas.drawRoundRect(mStrokeRect, sStrokeWidth, sStrokeWidth, sStrokePaint);
michael@0 114 }
michael@0 115
michael@0 116 /**
michael@0 117 * Formats the image for display, if the prerequisite data are available. Upscales tiny Favicons to
michael@0 118 * normal sized ones, replaces null bitmaps with the default Favicon, and fills all remaining space
michael@0 119 * in this view with the coloured background.
michael@0 120 */
michael@0 121 private void formatImage() {
michael@0 122 // If we're called before bitmap is set, or before size is set, show blank.
michael@0 123 if (mIconBitmap == null || mActualWidth == 0 || mActualHeight == 0) {
michael@0 124 showNoImage();
michael@0 125 return;
michael@0 126 }
michael@0 127
michael@0 128 if (mScalingExpected && mActualWidth != mIconBitmap.getWidth()) {
michael@0 129 scaleBitmap();
michael@0 130 // Don't scale the image every time something changes.
michael@0 131 mScalingExpected = false;
michael@0 132 }
michael@0 133
michael@0 134 setImageBitmap(mIconBitmap);
michael@0 135
michael@0 136 // After scaling, determine if we have empty space around the scaled image which we need to
michael@0 137 // fill with the coloured background. If applicable, show it.
michael@0 138 // We assume Favicons are still squares and only bother with the background if more than 3px
michael@0 139 // of it would be displayed.
michael@0 140 if (Math.abs(mIconBitmap.getWidth() - mActualWidth) > 3) {
michael@0 141 mDominantColor = Favicons.getFaviconColor(mIconKey);
michael@0 142 if (mDominantColor == -1) {
michael@0 143 mDominantColor = 0;
michael@0 144 }
michael@0 145 } else {
michael@0 146 mDominantColor = 0;
michael@0 147 }
michael@0 148 }
michael@0 149
michael@0 150 private void scaleBitmap() {
michael@0 151 // If the Favicon can be resized to fill the view exactly without an enlargment of more than
michael@0 152 // a factor of two, do so.
michael@0 153 int doubledSize = mIconBitmap.getWidth()*2;
michael@0 154 if (mActualWidth > doubledSize) {
michael@0 155 // If the view is more than twice the size of the image, just double the image size
michael@0 156 // and do the rest with padding.
michael@0 157 mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, doubledSize, doubledSize, true);
michael@0 158 } else {
michael@0 159 // Otherwise, scale the image to fill the view.
michael@0 160 mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, mActualWidth, mActualWidth, true);
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 /**
michael@0 165 * Sets the icon displayed in this Favicon view to the bitmap provided. If the size of the view
michael@0 166 * has been set, the display will be updated right away, otherwise the update will be deferred
michael@0 167 * until then. The key provided is used to cache the result of the calculation of the dominant
michael@0 168 * colour of the provided image - this value is used to draw the coloured background in this view
michael@0 169 * if the icon is not large enough to fill it.
michael@0 170 *
michael@0 171 * @param bitmap favicon image
michael@0 172 * @param key string used as a key to cache the dominant color of this image
michael@0 173 * @param allowScaling If true, allows the provided bitmap to be scaled by this FaviconView.
michael@0 174 * Typically, you should prefer using Favicons obtained via the caching system
michael@0 175 * (Favicons class), so as to exploit caching.
michael@0 176 */
michael@0 177 private void updateImageInternal(Bitmap bitmap, String key, boolean allowScaling) {
michael@0 178 if (bitmap == null) {
michael@0 179 showDefaultFavicon();
michael@0 180 return;
michael@0 181 }
michael@0 182
michael@0 183 // Reassigning the same bitmap? Don't bother.
michael@0 184 if (mUnscaledBitmap == bitmap) {
michael@0 185 return;
michael@0 186 }
michael@0 187 mUnscaledBitmap = bitmap;
michael@0 188 mIconBitmap = bitmap;
michael@0 189 mIconKey = key;
michael@0 190 mScalingExpected = allowScaling;
michael@0 191
michael@0 192 // Possibly update the display.
michael@0 193 formatImage();
michael@0 194 }
michael@0 195
michael@0 196 public void showDefaultFavicon() {
michael@0 197 setImageResource(R.drawable.favicon);
michael@0 198 mDominantColor = 0;
michael@0 199 }
michael@0 200
michael@0 201 private void showNoImage() {
michael@0 202 setImageDrawable(null);
michael@0 203 mDominantColor = 0;
michael@0 204 }
michael@0 205
michael@0 206 /**
michael@0 207 * Clear image and background shown by this view.
michael@0 208 */
michael@0 209 public void clearImage() {
michael@0 210 showNoImage();
michael@0 211 mUnscaledBitmap = null;
michael@0 212 mIconBitmap = null;
michael@0 213 mIconKey = null;
michael@0 214 mScalingExpected = false;
michael@0 215 }
michael@0 216
michael@0 217 /**
michael@0 218 * Update the displayed image and apply the scaling logic.
michael@0 219 * The scaling logic will attempt to resize the image to fit correctly inside the view in a way
michael@0 220 * that avoids unreasonable levels of loss of quality.
michael@0 221 * Scaling is necessary only when the icon being provided is not drawn from the Favicon cache
michael@0 222 * introduced in Bug 914296.
michael@0 223 *
michael@0 224 * Due to Bug 913746, icons bundled for search engines are not available to the cache, so must
michael@0 225 * always have the scaling logic applied here. At the time of writing, this is the only case in
michael@0 226 * which the scaling logic here is applied.
michael@0 227 *
michael@0 228 * @param bitmap The bitmap to display in this favicon view.
michael@0 229 * @param key The key to use into the dominant colours cache when selecting a background colour.
michael@0 230 */
michael@0 231 public void updateAndScaleImage(Bitmap bitmap, String key) {
michael@0 232 updateImageInternal(bitmap, key, true);
michael@0 233 }
michael@0 234
michael@0 235 /**
michael@0 236 * Update the image displayed in the Favicon view without scaling. Images larger than the view
michael@0 237 * will be centrally cropped. Images smaller than the view will be placed centrally and the
michael@0 238 * extra space filled with the dominant colour of the provided image.
michael@0 239 *
michael@0 240 * @param bitmap The bitmap to display in this favicon view.
michael@0 241 * @param key The key to use into the dominant colours cache when selecting a background colour.
michael@0 242 */
michael@0 243 public void updateImage(Bitmap bitmap, String key) {
michael@0 244 updateImageInternal(bitmap, key, false);
michael@0 245 }
michael@0 246
michael@0 247 public Bitmap getBitmap() {
michael@0 248 return mIconBitmap;
michael@0 249 }
michael@0 250 }

mercurial