mobile/android/thirdparty/com/squareup/picasso/RequestCreator.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 /*
michael@0 2 * Copyright (C) 2013 Square, Inc.
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16 package com.squareup.picasso;
michael@0 17
michael@0 18 import android.content.res.Resources;
michael@0 19 import android.graphics.Bitmap;
michael@0 20 import android.graphics.drawable.Drawable;
michael@0 21 import android.net.Uri;
michael@0 22 import android.widget.ImageView;
michael@0 23 import java.io.IOException;
michael@0 24
michael@0 25 import static com.squareup.picasso.BitmapHunter.forRequest;
michael@0 26 import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY;
michael@0 27 import static com.squareup.picasso.Utils.checkNotMain;
michael@0 28 import static com.squareup.picasso.Utils.createKey;
michael@0 29
michael@0 30 /** Fluent API for building an image download request. */
michael@0 31 @SuppressWarnings("UnusedDeclaration") // Public API.
michael@0 32 public class RequestCreator {
michael@0 33 private final Picasso picasso;
michael@0 34 private final Request.Builder data;
michael@0 35
michael@0 36 private boolean skipMemoryCache;
michael@0 37 private boolean noFade;
michael@0 38 private boolean deferred;
michael@0 39 private int placeholderResId;
michael@0 40 private Drawable placeholderDrawable;
michael@0 41 private int errorResId;
michael@0 42 private Drawable errorDrawable;
michael@0 43
michael@0 44 RequestCreator(Picasso picasso, Uri uri, int resourceId) {
michael@0 45 if (picasso.shutdown) {
michael@0 46 throw new IllegalStateException(
michael@0 47 "Picasso instance already shut down. Cannot submit new requests.");
michael@0 48 }
michael@0 49 this.picasso = picasso;
michael@0 50 this.data = new Request.Builder(uri, resourceId);
michael@0 51 }
michael@0 52
michael@0 53 /**
michael@0 54 * A placeholder drawable to be used while the image is being loaded. If the requested image is
michael@0 55 * not immediately available in the memory cache then this resource will be set on the target
michael@0 56 * {@link ImageView}.
michael@0 57 */
michael@0 58 public RequestCreator placeholder(int placeholderResId) {
michael@0 59 if (placeholderResId == 0) {
michael@0 60 throw new IllegalArgumentException("Placeholder image resource invalid.");
michael@0 61 }
michael@0 62 if (placeholderDrawable != null) {
michael@0 63 throw new IllegalStateException("Placeholder image already set.");
michael@0 64 }
michael@0 65 this.placeholderResId = placeholderResId;
michael@0 66 return this;
michael@0 67 }
michael@0 68
michael@0 69 /**
michael@0 70 * A placeholder drawable to be used while the image is being loaded. If the requested image is
michael@0 71 * not immediately available in the memory cache then this resource will be set on the target
michael@0 72 * {@link ImageView}.
michael@0 73 * <p>
michael@0 74 * If you are not using a placeholder image but want to clear an existing image (such as when
michael@0 75 * used in an {@link android.widget.Adapter adapter}), pass in {@code null}.
michael@0 76 */
michael@0 77 public RequestCreator placeholder(Drawable placeholderDrawable) {
michael@0 78 if (placeholderResId != 0) {
michael@0 79 throw new IllegalStateException("Placeholder image already set.");
michael@0 80 }
michael@0 81 this.placeholderDrawable = placeholderDrawable;
michael@0 82 return this;
michael@0 83 }
michael@0 84
michael@0 85 /** An error drawable to be used if the request image could not be loaded. */
michael@0 86 public RequestCreator error(int errorResId) {
michael@0 87 if (errorResId == 0) {
michael@0 88 throw new IllegalArgumentException("Error image resource invalid.");
michael@0 89 }
michael@0 90 if (errorDrawable != null) {
michael@0 91 throw new IllegalStateException("Error image already set.");
michael@0 92 }
michael@0 93 this.errorResId = errorResId;
michael@0 94 return this;
michael@0 95 }
michael@0 96
michael@0 97 /** An error drawable to be used if the request image could not be loaded. */
michael@0 98 public RequestCreator error(Drawable errorDrawable) {
michael@0 99 if (errorDrawable == null) {
michael@0 100 throw new IllegalArgumentException("Error image may not be null.");
michael@0 101 }
michael@0 102 if (errorResId != 0) {
michael@0 103 throw new IllegalStateException("Error image already set.");
michael@0 104 }
michael@0 105 this.errorDrawable = errorDrawable;
michael@0 106 return this;
michael@0 107 }
michael@0 108
michael@0 109 /**
michael@0 110 * Attempt to resize the image to fit exactly into the target {@link ImageView}'s bounds. This
michael@0 111 * will result in delayed execution of the request until the {@link ImageView} has been measured.
michael@0 112 * <p/>
michael@0 113 * <em>Note:</em> This method works only when your target is an {@link ImageView}.
michael@0 114 */
michael@0 115 public RequestCreator fit() {
michael@0 116 deferred = true;
michael@0 117 return this;
michael@0 118 }
michael@0 119
michael@0 120 /** Internal use only. Used by {@link DeferredRequestCreator}. */
michael@0 121 RequestCreator unfit() {
michael@0 122 deferred = false;
michael@0 123 return this;
michael@0 124 }
michael@0 125
michael@0 126 /** Resize the image to the specified dimension size. */
michael@0 127 public RequestCreator resizeDimen(int targetWidthResId, int targetHeightResId) {
michael@0 128 Resources resources = picasso.context.getResources();
michael@0 129 int targetWidth = resources.getDimensionPixelSize(targetWidthResId);
michael@0 130 int targetHeight = resources.getDimensionPixelSize(targetHeightResId);
michael@0 131 return resize(targetWidth, targetHeight);
michael@0 132 }
michael@0 133
michael@0 134 /** Resize the image to the specified size in pixels. */
michael@0 135 public RequestCreator resize(int targetWidth, int targetHeight) {
michael@0 136 data.resize(targetWidth, targetHeight);
michael@0 137 return this;
michael@0 138 }
michael@0 139
michael@0 140 /**
michael@0 141 * Crops an image inside of the bounds specified by {@link #resize(int, int)} rather than
michael@0 142 * distorting the aspect ratio. This cropping technique scales the image so that it fills the
michael@0 143 * requested bounds and then crops the extra.
michael@0 144 */
michael@0 145 public RequestCreator centerCrop() {
michael@0 146 data.centerCrop();
michael@0 147 return this;
michael@0 148 }
michael@0 149
michael@0 150 /**
michael@0 151 * Centers an image inside of the bounds specified by {@link #resize(int, int)}. This scales
michael@0 152 * the image so that both dimensions are equal to or less than the requested bounds.
michael@0 153 */
michael@0 154 public RequestCreator centerInside() {
michael@0 155 data.centerInside();
michael@0 156 return this;
michael@0 157 }
michael@0 158
michael@0 159 /** Rotate the image by the specified degrees. */
michael@0 160 public RequestCreator rotate(float degrees) {
michael@0 161 data.rotate(degrees);
michael@0 162 return this;
michael@0 163 }
michael@0 164
michael@0 165 /** Rotate the image by the specified degrees around a pivot point. */
michael@0 166 public RequestCreator rotate(float degrees, float pivotX, float pivotY) {
michael@0 167 data.rotate(degrees, pivotX, pivotY);
michael@0 168 return this;
michael@0 169 }
michael@0 170
michael@0 171 /**
michael@0 172 * Add a custom transformation to be applied to the image.
michael@0 173 * <p/>
michael@0 174 * Custom transformations will always be run after the built-in transformations.
michael@0 175 */
michael@0 176 // TODO show example of calling resize after a transform in the javadoc
michael@0 177 public RequestCreator transform(Transformation transformation) {
michael@0 178 data.transform(transformation);
michael@0 179 return this;
michael@0 180 }
michael@0 181
michael@0 182 /**
michael@0 183 * Indicate that this action should not use the memory cache for attempting to load or save the
michael@0 184 * image. This can be useful when you know an image will only ever be used once (e.g., loading
michael@0 185 * an image from the filesystem and uploading to a remote server).
michael@0 186 */
michael@0 187 public RequestCreator skipMemoryCache() {
michael@0 188 skipMemoryCache = true;
michael@0 189 return this;
michael@0 190 }
michael@0 191
michael@0 192 /** Disable brief fade in of images loaded from the disk cache or network. */
michael@0 193 public RequestCreator noFade() {
michael@0 194 noFade = true;
michael@0 195 return this;
michael@0 196 }
michael@0 197
michael@0 198 /** Synchronously fulfill this request. Must not be called from the main thread. */
michael@0 199 public Bitmap get() throws IOException {
michael@0 200 checkNotMain();
michael@0 201 if (deferred) {
michael@0 202 throw new IllegalStateException("Fit cannot be used with get.");
michael@0 203 }
michael@0 204 if (!data.hasImage()) {
michael@0 205 return null;
michael@0 206 }
michael@0 207
michael@0 208 Request finalData = picasso.transformRequest(data.build());
michael@0 209 String key = createKey(finalData);
michael@0 210
michael@0 211 Action action = new GetAction(picasso, finalData, skipMemoryCache, key);
michael@0 212 return forRequest(picasso.context, picasso, picasso.dispatcher, picasso.cache, picasso.stats,
michael@0 213 action, picasso.dispatcher.downloader).hunt();
michael@0 214 }
michael@0 215
michael@0 216 /**
michael@0 217 * Asynchronously fulfills the request without a {@link ImageView} or {@link Target}. This is
michael@0 218 * useful when you want to warm up the cache with an image.
michael@0 219 */
michael@0 220 public void fetch() {
michael@0 221 if (deferred) {
michael@0 222 throw new IllegalStateException("Fit cannot be used with fetch.");
michael@0 223 }
michael@0 224 if (data.hasImage()) {
michael@0 225 Request finalData = picasso.transformRequest(data.build());
michael@0 226 String key = createKey(finalData);
michael@0 227
michael@0 228 Action action = new FetchAction(picasso, finalData, skipMemoryCache, key);
michael@0 229 picasso.enqueueAndSubmit(action);
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 /**
michael@0 234 * Asynchronously fulfills the request into the specified {@link Target}. In most cases, you
michael@0 235 * should use this when you are dealing with a custom {@link android.view.View View} or view
michael@0 236 * holder which should implement the {@link Target} interface.
michael@0 237 * <p>
michael@0 238 * Implementing on a {@link android.view.View View}:
michael@0 239 * <blockquote><pre>
michael@0 240 * public class ProfileView extends FrameLayout implements Target {
michael@0 241 * {@literal @}Override public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from) {
michael@0 242 * setBackgroundDrawable(new BitmapDrawable(bitmap));
michael@0 243 * }
michael@0 244 *
michael@0 245 * {@literal @}Override public void onBitmapFailed() {
michael@0 246 * setBackgroundResource(R.drawable.profile_error);
michael@0 247 * }
michael@0 248 * }
michael@0 249 * </pre></blockquote>
michael@0 250 * Implementing on a view holder object for use inside of an adapter:
michael@0 251 * <blockquote><pre>
michael@0 252 * public class ViewHolder implements Target {
michael@0 253 * public FrameLayout frame;
michael@0 254 * public TextView name;
michael@0 255 *
michael@0 256 * {@literal @}Override public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from) {
michael@0 257 * frame.setBackgroundDrawable(new BitmapDrawable(bitmap));
michael@0 258 * }
michael@0 259 *
michael@0 260 * {@literal @}Override public void onBitmapFailed() {
michael@0 261 * frame.setBackgroundResource(R.drawable.profile_error);
michael@0 262 * }
michael@0 263 * }
michael@0 264 * </pre></blockquote>
michael@0 265 * <p>
michael@0 266 * <em>Note:</em> This method keeps a weak reference to the {@link Target} instance and will be
michael@0 267 * garbage collected if you do not keep a strong reference to it. To receive callbacks when an
michael@0 268 * image is loaded use {@link #into(android.widget.ImageView, Callback)}.
michael@0 269 */
michael@0 270 public void into(Target target) {
michael@0 271 if (target == null) {
michael@0 272 throw new IllegalArgumentException("Target must not be null.");
michael@0 273 }
michael@0 274 if (deferred) {
michael@0 275 throw new IllegalStateException("Fit cannot be used with a Target.");
michael@0 276 }
michael@0 277
michael@0 278 Drawable drawable =
michael@0 279 placeholderResId != 0 ? picasso.context.getResources().getDrawable(placeholderResId)
michael@0 280 : placeholderDrawable;
michael@0 281
michael@0 282 if (!data.hasImage()) {
michael@0 283 picasso.cancelRequest(target);
michael@0 284 target.onPrepareLoad(drawable);
michael@0 285 return;
michael@0 286 }
michael@0 287
michael@0 288 Request finalData = picasso.transformRequest(data.build());
michael@0 289 String requestKey = createKey(finalData);
michael@0 290
michael@0 291 if (!skipMemoryCache) {
michael@0 292 Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
michael@0 293 if (bitmap != null) {
michael@0 294 picasso.cancelRequest(target);
michael@0 295 target.onBitmapLoaded(bitmap, MEMORY);
michael@0 296 return;
michael@0 297 }
michael@0 298 }
michael@0 299
michael@0 300 target.onPrepareLoad(drawable);
michael@0 301
michael@0 302 Action action = new TargetAction(picasso, target, finalData, skipMemoryCache, requestKey);
michael@0 303 picasso.enqueueAndSubmit(action);
michael@0 304 }
michael@0 305
michael@0 306 /**
michael@0 307 * Asynchronously fulfills the request into the specified {@link ImageView}.
michael@0 308 * <p/>
michael@0 309 * <em>Note:</em> This method keeps a weak reference to the {@link ImageView} instance and will
michael@0 310 * automatically support object recycling.
michael@0 311 */
michael@0 312 public void into(ImageView target) {
michael@0 313 into(target, null);
michael@0 314 }
michael@0 315
michael@0 316 /**
michael@0 317 * Asynchronously fulfills the request into the specified {@link ImageView} and invokes the
michael@0 318 * target {@link Callback} if it's not {@code null}.
michael@0 319 * <p/>
michael@0 320 * <em>Note:</em> The {@link Callback} param is a strong reference and will prevent your
michael@0 321 * {@link android.app.Activity} or {@link android.app.Fragment} from being garbage collected. If
michael@0 322 * you use this method, it is <b>strongly</b> recommended you invoke an adjacent
michael@0 323 * {@link Picasso#cancelRequest(android.widget.ImageView)} call to prevent temporary leaking.
michael@0 324 */
michael@0 325 public void into(ImageView target, Callback callback) {
michael@0 326 if (target == null) {
michael@0 327 throw new IllegalArgumentException("Target must not be null.");
michael@0 328 }
michael@0 329
michael@0 330 if (!data.hasImage()) {
michael@0 331 picasso.cancelRequest(target);
michael@0 332 PicassoDrawable.setPlaceholder(target, placeholderResId, placeholderDrawable);
michael@0 333 return;
michael@0 334 }
michael@0 335
michael@0 336 if (deferred) {
michael@0 337 if (data.hasSize()) {
michael@0 338 throw new IllegalStateException("Fit cannot be used with resize.");
michael@0 339 }
michael@0 340 int measuredWidth = target.getMeasuredWidth();
michael@0 341 int measuredHeight = target.getMeasuredHeight();
michael@0 342 if (measuredWidth == 0 || measuredHeight == 0) {
michael@0 343 PicassoDrawable.setPlaceholder(target, placeholderResId, placeholderDrawable);
michael@0 344 picasso.defer(target, new DeferredRequestCreator(this, target, callback));
michael@0 345 return;
michael@0 346 }
michael@0 347 data.resize(measuredWidth, measuredHeight);
michael@0 348 }
michael@0 349
michael@0 350 Request finalData = picasso.transformRequest(data.build());
michael@0 351 String requestKey = createKey(finalData);
michael@0 352
michael@0 353 if (!skipMemoryCache) {
michael@0 354 Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
michael@0 355 if (bitmap != null) {
michael@0 356 picasso.cancelRequest(target);
michael@0 357 PicassoDrawable.setBitmap(target, picasso.context, bitmap, MEMORY, noFade,
michael@0 358 picasso.debugging);
michael@0 359 if (callback != null) {
michael@0 360 callback.onSuccess();
michael@0 361 }
michael@0 362 return;
michael@0 363 }
michael@0 364 }
michael@0 365
michael@0 366 PicassoDrawable.setPlaceholder(target, placeholderResId, placeholderDrawable);
michael@0 367
michael@0 368 Action action =
michael@0 369 new ImageViewAction(picasso, target, finalData, skipMemoryCache, noFade, errorResId,
michael@0 370 errorDrawable, requestKey, callback);
michael@0 371
michael@0 372 picasso.enqueueAndSubmit(action);
michael@0 373 }
michael@0 374 }

mercurial