@nativescript-community/ui-image 4.6.6 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -20
  3. package/index-common.d.ts +47 -18
  4. package/index-common.js +5 -69
  5. package/index-common.js.map +1 -1
  6. package/index.android.d.ts +33 -60
  7. package/index.android.js +597 -702
  8. package/index.android.js.map +1 -1
  9. package/index.d.ts +17 -92
  10. package/index.ios.d.ts +5 -10
  11. package/index.ios.js +72 -54
  12. package/index.ios.js.map +1 -1
  13. package/package.json +4 -4
  14. package/platforms/android/include.gradle +21 -16
  15. package/platforms/android/java/com/nativescript/image/CacheKeyStore.java +65 -0
  16. package/platforms/android/java/com/nativescript/image/CapturingEngineKeyFactory.java +43 -0
  17. package/platforms/android/java/com/nativescript/image/CompositeRequestListener.java +58 -0
  18. package/platforms/android/java/com/nativescript/image/ConditionalCrossFadeFactory.java +33 -0
  19. package/platforms/android/java/com/nativescript/image/CustomDataFetcher.java +124 -0
  20. package/platforms/android/java/com/nativescript/image/CustomGlideModule.java +220 -0
  21. package/platforms/android/java/com/nativescript/image/CustomGlideUrl.java +52 -0
  22. package/platforms/android/java/com/nativescript/image/CustomUrlLoader.java +74 -0
  23. package/platforms/android/java/com/nativescript/image/EvictionManager.java +735 -0
  24. package/platforms/android/java/com/nativescript/image/ExtractRequestOptions.java +109 -0
  25. package/platforms/android/java/com/nativescript/image/ImageLoadSourceCallback.java +5 -0
  26. package/platforms/android/java/com/nativescript/image/ImageProgressCallback.java +5 -0
  27. package/platforms/android/java/com/nativescript/image/LoadSourceInterceptor.java +28 -0
  28. package/platforms/android/java/com/nativescript/image/MatrixDrawable.java +200 -0
  29. package/platforms/android/java/com/nativescript/image/MatrixDrawableImageViewTarget.java +154 -0
  30. package/platforms/android/java/com/nativescript/image/MatrixImageView.java +696 -0
  31. package/platforms/android/java/com/nativescript/image/ProgressInterceptor.java +25 -0
  32. package/platforms/android/java/com/nativescript/image/ProgressResponseBody.java +70 -0
  33. package/platforms/android/java/com/nativescript/image/RecordingDigest.java +48 -0
  34. package/platforms/android/java/com/nativescript/image/RecreatedResourceKey.java +95 -0
  35. package/platforms/android/java/com/nativescript/image/SaveKeysRequestListener.java +145 -0
  36. package/platforms/android/java/com/nativescript/image/ScaleUtils.java +129 -0
  37. package/platforms/android/java/com/nativescript/image/SharedPrefCacheKeyStore.java +92 -0
  38. package/platforms/android/native-api-usage.json +39 -37
  39. package/platforms/ios/Podfile +1 -1
  40. package/references.d.ts +0 -1
  41. package/tsconfig.tsbuildinfo +1 -1
  42. package/typings/android.d.ts +4 -27
  43. package/typings/glide.android.d.ts +9395 -0
  44. package/typings/glide.okhttp.android.d.ts +104 -0
  45. package/typings/glide.transform.android.d.ts +540 -0
  46. package/typings/ui_image.android.d.ts +517 -0
  47. package/platforms/android/java/com/nativescript/image/BaseDataSubscriber.java +0 -22
  48. package/platforms/android/java/com/nativescript/image/BaseDataSubscriberListener.java +0 -9
  49. package/platforms/android/java/com/nativescript/image/DraweeView.java +0 -371
  50. package/platforms/android/java/com/nativescript/image/NetworkImageRequest.java +0 -55
  51. package/platforms/android/java/com/nativescript/image/OkHttpNetworkFetcher.java +0 -56
  52. package/platforms/android/java/com/nativescript/image/ScalingBlurPostprocessor.java +0 -64
  53. package/platforms/android/java/com/nativescript/image/ScalingUtils.java +0 -519
  54. package/typings/fresco-processors.d.ts +0 -53
  55. package/typings/fresco.d.ts +0 -12070
@@ -0,0 +1,735 @@
1
+ package com.nativescript.image;
2
+
3
+ import android.os.Handler;
4
+ import android.os.Looper;
5
+ import androidx.annotation.GuardedBy;
6
+ import androidx.annotation.MainThread;
7
+ import androidx.annotation.Nullable;
8
+ import com.bumptech.glide.load.Key;
9
+ import com.bumptech.glide.load.Options;
10
+ import com.bumptech.glide.load.Transformation;
11
+ import com.bumptech.glide.load.engine.cache.DiskCache;
12
+ import com.bumptech.glide.load.engine.cache.MemoryCache;
13
+ import com.bumptech.glide.load.engine.cache.LruResourceCache;
14
+ import java.util.concurrent.ExecutorService;
15
+ import java.util.concurrent.Executors;
16
+ import java.util.concurrent.atomic.AtomicBoolean;
17
+ import java.util.concurrent.atomic.AtomicInteger;
18
+ import java.util.concurrent.atomic.AtomicReference;
19
+
20
+ import android.util.Log;
21
+
22
+ /**
23
+ * EvictionManager (updated)
24
+ *
25
+ * - adds clearDiskCache/clearMemory/clearAll with callback overloads
26
+ * - adds disk-only / memory-only evict methods
27
+ * - uses recorded transformation/options key bytes to recreate transformed
28
+ * cache keys
29
+ * - EvictionCallback now reports an optional Exception (first encountered) in
30
+ * addition to success flag
31
+ *
32
+ * Notes:
33
+ * - Disk operations run on a background executor.
34
+ * - Memory ops run on the main thread.
35
+ * - Callbacks are always posted on the main thread.
36
+ */
37
+ public final class EvictionManager {
38
+ private static final String TAG = "EvictionManager";
39
+ private static final EvictionManager INSTANCE = new EvictionManager();
40
+
41
+ private final ExecutorService diskExecutor = Executors.newSingleThreadExecutor();
42
+ private final Handler mainHandler = new Handler(Looper.getMainLooper());
43
+
44
+ @GuardedBy("this")
45
+ private DiskCache diskCache;
46
+ @GuardedBy("this")
47
+ private LruResourceCache memoryCache;
48
+
49
+ // in-memory store for captured info and engineKey object
50
+ private final CacheKeyStore inMemoryKeyStore = new CacheKeyStore();
51
+
52
+ // optional persistent store (SharedPref). If null, fallback to in-memory only.
53
+ @Nullable
54
+ private SharedPrefCacheKeyStore persistentStore;
55
+
56
+ private EvictionManager() {
57
+ }
58
+
59
+ public static EvictionManager get() {
60
+ return INSTANCE;
61
+ }
62
+
63
+ public synchronized void setDiskCache(DiskCache diskCache) {
64
+ this.diskCache = diskCache;
65
+ }
66
+
67
+ public synchronized void setMemoryCache(LruResourceCache memoryCache) {
68
+ this.memoryCache = memoryCache;
69
+ }
70
+
71
+ public synchronized void setPersistentStore(@Nullable SharedPrefCacheKeyStore store) {
72
+ this.persistentStore = store;
73
+ }
74
+
75
+ /**
76
+ * Expose the in-memory store so callers/listeners can put engineKey objects
77
+ * there.
78
+ */
79
+ public CacheKeyStore getKeyStore() {
80
+ return inMemoryKeyStore;
81
+ }
82
+
83
+ /**
84
+ * Save keys (mirrors into persistent store if configured).
85
+ */
86
+ public synchronized void saveKeys(final String id, final CacheKeyStore.StoredKeys newStored) {
87
+ if (id == null || newStored == null) {
88
+ Log.w(TAG, "saveKeys called with null id or newStored");
89
+ return;
90
+ }
91
+
92
+ try {
93
+ // 1) Load existing stored keys (check persistent store first, fallback to
94
+ // in-memory)
95
+ CacheKeyStore.StoredKeys existing = null;
96
+ if (persistentStore != null) {
97
+ existing = persistentStore.get(id);
98
+ }
99
+ if (existing == null) {
100
+ existing = inMemoryKeyStore.get(id);
101
+ }
102
+
103
+ // 2) If existing has an engineKey and newStored doesn't, merge the engineKey in
104
+ CacheKeyStore.StoredKeys toPersist = newStored;
105
+ if (existing != null && existing.engineKey != null && toPersist.engineKey == null) {
106
+ // create a new StoredKeys that is identical to newStored but keeps
107
+ // existing.engineKey
108
+ toPersist = new CacheKeyStore.StoredKeys(
109
+ toPersist.sourceKey,
110
+ toPersist.signature,
111
+ toPersist.width,
112
+ toPersist.height,
113
+ toPersist.transformation,
114
+ toPersist.transformationKeyBytes,
115
+ toPersist.decodedResourceClass,
116
+ toPersist.options,
117
+ toPersist.optionsKeyBytes,
118
+ existing.engineKey // preserve captured engine key
119
+ );
120
+ }
121
+
122
+ // 3) Persist to persistent store if available, else to in-memory store
123
+ if (persistentStore != null) {
124
+ persistentStore.put(id, toPersist);
125
+ } else {
126
+ inMemoryKeyStore.put(id, toPersist);
127
+ }
128
+ } catch (Throwable t) {
129
+ Log.w(TAG, "saveKeys failed for id=" + id, t);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Eviction completion callback (always invoked on main thread).
135
+ *
136
+ * The second argument is the first Exception encountered during the operation
137
+ * (if any).
138
+ */
139
+ public interface EvictionCallback {
140
+ void onComplete(boolean success, @Nullable Exception error);
141
+ }
142
+
143
+ /** Disk presence callback for async check. */
144
+ public interface DiskPresenceCallback {
145
+ void onResult(boolean sourcePresent, boolean transformedPresent);
146
+ }
147
+
148
+ // -----------------------
149
+ // New: clear APIs
150
+ // -----------------------
151
+
152
+ /**
153
+ * Clear the entire disk cache. Runs on a background thread. Callback invoked on
154
+ * main thread.
155
+ */
156
+ public void clearDiskCache(@Nullable final EvictionCallback callback) {
157
+ diskExecutor.execute(() -> {
158
+ boolean success = true;
159
+ Exception ex = null;
160
+ DiskCache dc;
161
+ synchronized (EvictionManager.this) {
162
+ dc = diskCache;
163
+ }
164
+ if (dc != null) {
165
+ try {
166
+ dc.clear();
167
+ } catch (Exception e) {
168
+ success = false;
169
+ ex = e;
170
+ }
171
+ }
172
+ if (callback != null) {
173
+ final boolean finalSuccess = success;
174
+ final Exception finalEx = ex;
175
+ mainHandler.post(() -> callback.onComplete(finalSuccess, finalEx));
176
+ }
177
+ });
178
+ }
179
+
180
+ /** Clear disk cache without callback. */
181
+ public void clearDiskCache() {
182
+ clearDiskCache(null);
183
+ }
184
+
185
+ /**
186
+ * Clear the entire memory cache. This must be invoked on the main thread (we
187
+ * post to main to
188
+ * guarantee it). Callback invoked on main thread.
189
+ */
190
+ public void clearMemory(@Nullable final EvictionCallback callback) {
191
+ mainHandler.post(() -> {
192
+ boolean success = true;
193
+ Exception ex = null;
194
+ LruResourceCache mc;
195
+ synchronized (EvictionManager.this) {
196
+ mc = memoryCache;
197
+ }
198
+ if (mc != null) {
199
+ try {
200
+ mc.clearMemory();
201
+ } catch (Exception e) {
202
+ success = false;
203
+ ex = e;
204
+ }
205
+ }
206
+ if (callback != null) {
207
+ callback.onComplete(success, ex);
208
+ }
209
+ });
210
+ }
211
+
212
+ /** Clear memory cache without callback. */
213
+ public void clearMemory() {
214
+ clearMemory(null);
215
+ }
216
+
217
+ /**
218
+ * Clear both disk and memory caches. Disk clear runs first on background
219
+ * executor; when disk clear
220
+ * finishes we clear memory on the main thread. Callback invoked on main with
221
+ * combined success and
222
+ * the first exception encountered (if any).
223
+ */
224
+ public void clearAll(@Nullable final EvictionCallback callback) {
225
+ diskExecutor.execute(() -> {
226
+ boolean diskSuccess = true;
227
+ Exception firstEx = null;
228
+ DiskCache dc;
229
+ synchronized (EvictionManager.this) {
230
+ dc = diskCache;
231
+ }
232
+ if (dc != null) {
233
+ try {
234
+ dc.clear();
235
+ } catch (Exception e) {
236
+ diskSuccess = false;
237
+ firstEx = e;
238
+ }
239
+ }
240
+ final boolean finalDiskSuccess = diskSuccess;
241
+ final Exception finalFirstEx = firstEx;
242
+ mainHandler.post(() -> {
243
+ boolean memSuccess = true;
244
+ Exception memEx = null;
245
+ LruResourceCache mc;
246
+ synchronized (EvictionManager.this) {
247
+ mc = memoryCache;
248
+ }
249
+ if (mc != null) {
250
+ try {
251
+ mc.clearMemory();
252
+ } catch (Exception e) {
253
+ memSuccess = false;
254
+ if (finalFirstEx == null)
255
+ memEx = e;
256
+ }
257
+ }
258
+ boolean combined = finalDiskSuccess && memSuccess;
259
+ Exception combinedEx = finalFirstEx != null ? finalFirstEx : memEx;
260
+ if (callback != null)
261
+ callback.onComplete(combined, combinedEx);
262
+ });
263
+ });
264
+ }
265
+
266
+ /** Clear both disk and memory without callback. */
267
+ public void clearAll() {
268
+ clearAll(null);
269
+ }
270
+
271
+ // -----------------------
272
+ // Eviction-by-id APIs
273
+ // -----------------------
274
+
275
+ /**
276
+ * Evict both disk (source + transformed) and memory for id. Callback invoked on
277
+ * main thread.
278
+ */
279
+ public void evictAllForId(final String id, @Nullable final EvictionCallback callback) {
280
+ final CacheKeyStore.StoredKeys s = readStoredKeysPreferPersistent(id);
281
+ if (s == null) {
282
+ // fallback conservative attempt (source only)
283
+ evictDiskForId(id, callback);
284
+ return;
285
+ }
286
+ final byte[] transformationBytes = getTransformationBytesFromStoredKeys(s);
287
+ final byte[] optionsBytes = s.optionsKeyBytes;
288
+ performEvictionTasks(
289
+ s.sourceKey,
290
+ s.signature,
291
+ s.width,
292
+ s.height,
293
+ transformationBytes,
294
+ s.decodedResourceClass,
295
+ optionsBytes,
296
+ s.engineKey,
297
+ callback);
298
+ }
299
+
300
+ /** Backwards-compatible no-callback variant */
301
+ public void evictAllForId(final String id) {
302
+ evictAllForId(id, null);
303
+ }
304
+
305
+ /**
306
+ * Evict from disk (source + transformed). Callback invoked on main thread.
307
+ */
308
+ public void evictDiskForId(final String id, @Nullable final EvictionCallback callback) {
309
+ final CacheKeyStore.StoredKeys s = readStoredKeysPreferPersistent(id);
310
+ if (s == null) {
311
+ // fallback to deleting source by id-only ObjectKey
312
+ final Key fallbackSource = new com.bumptech.glide.signature.ObjectKey(id);
313
+ diskExecutor.execute(() -> {
314
+ boolean success = true;
315
+ Exception ex = null;
316
+ DiskCache dc;
317
+ synchronized (EvictionManager.this) {
318
+ dc = diskCache;
319
+ }
320
+ if (dc != null) {
321
+ try {
322
+ dc.delete(fallbackSource);
323
+ } catch (Exception e) {
324
+ success = false;
325
+ ex = e;
326
+ }
327
+ }
328
+ if (callback != null) {
329
+ final boolean finalSuccess = success;
330
+ final Exception finalEx = ex;
331
+ mainHandler.post(() -> callback.onComplete(finalSuccess, finalEx));
332
+ }
333
+ });
334
+ return;
335
+ }
336
+
337
+ diskExecutor.execute(() -> {
338
+ boolean success = true;
339
+ Exception ex = null;
340
+ DiskCache dc;
341
+ synchronized (EvictionManager.this) {
342
+ dc = diskCache;
343
+ }
344
+ if (dc != null) {
345
+ try {
346
+ dc.delete(s.sourceKey);
347
+ } catch (Exception e) {
348
+ success = false;
349
+ ex = e;
350
+ }
351
+ try {
352
+ Key resourceKey = new RecreatedResourceKey(
353
+ s.sourceKey,
354
+ s.signature,
355
+ s.width,
356
+ s.height,
357
+ getTransformationBytesFromStoredKeys(s),
358
+ s.decodedResourceClass,
359
+ s.optionsKeyBytes);
360
+ dc.delete(resourceKey);
361
+ } catch (Exception e) {
362
+ if (ex == null)
363
+ ex = e;
364
+ success = false;
365
+ }
366
+ }
367
+ if (callback != null) {
368
+ final boolean finalSuccess = success;
369
+ final Exception finalEx = ex;
370
+ mainHandler.post(() -> callback.onComplete(finalSuccess, finalEx));
371
+ }
372
+ });
373
+ }
374
+
375
+ /** Evict disk-only, no callback. */
376
+ public void evictDiskForId(final String id) {
377
+ evictDiskForId(id, null);
378
+ }
379
+
380
+ /** Evict only source/raw bytes (disk). */
381
+ public void evictSourceForId(final String id, @Nullable final EvictionCallback callback) {
382
+ final CacheKeyStore.StoredKeys s = readStoredKeysPreferPersistent(id);
383
+ final Key sourceKey = (s != null && s.sourceKey != null) ? s.sourceKey
384
+ : new com.bumptech.glide.signature.ObjectKey(id);
385
+ diskExecutor.execute(() -> {
386
+ boolean success = true;
387
+ Exception ex = null;
388
+ DiskCache dc;
389
+ synchronized (EvictionManager.this) {
390
+ dc = diskCache;
391
+ }
392
+ if (dc != null) {
393
+ try {
394
+ dc.delete(sourceKey);
395
+ } catch (Exception e) {
396
+ success = false;
397
+ ex = e;
398
+ }
399
+ }
400
+ if (callback != null) {
401
+ final boolean finalSuccess = success;
402
+ final Exception finalEx = ex;
403
+ mainHandler.post(() -> callback.onComplete(finalSuccess, finalEx));
404
+ }
405
+ });
406
+ }
407
+
408
+ /** Evict only the transformed resource (disk). */
409
+ public void evictTransformedForId(final String id, @Nullable final EvictionCallback callback) {
410
+ final CacheKeyStore.StoredKeys s = readStoredKeysPreferPersistent(id);
411
+ if (s == null) {
412
+ if (callback != null)
413
+ mainHandler.post(() -> callback.onComplete(false, null));
414
+ return;
415
+ }
416
+ final byte[] transformationBytes = getTransformationBytesFromStoredKeys(s);
417
+ final byte[] optionsBytes = s.optionsKeyBytes;
418
+
419
+ diskExecutor.execute(() -> {
420
+ boolean success = true;
421
+ Exception ex = null;
422
+ DiskCache dc;
423
+ synchronized (EvictionManager.this) {
424
+ dc = diskCache;
425
+ }
426
+ if (dc != null) {
427
+ try {
428
+ Key resourceKey = new RecreatedResourceKey(s.sourceKey, s.signature, s.width, s.height, transformationBytes,
429
+ s.decodedResourceClass, optionsBytes);
430
+ dc.delete(resourceKey);
431
+ } catch (Exception e) {
432
+ success = false;
433
+ ex = e;
434
+ }
435
+ }
436
+ if (callback != null) {
437
+ final boolean finalSuccess = success;
438
+ final Exception finalEx = ex;
439
+ mainHandler.post(() -> callback.onComplete(finalSuccess, finalEx));
440
+ }
441
+ });
442
+ }
443
+
444
+ /**
445
+ * Evict only from memory (must be called on main thread). Callback invoked on
446
+ * main thread.
447
+ */
448
+ @MainThread
449
+ public void evictMemoryForId(final String id, @Nullable final EvictionCallback callback) {
450
+ final CacheKeyStore.StoredKeys s = (persistentStore != null) ? persistentStore.get(id) : inMemoryKeyStore.get(id);
451
+ final Key engineKey = (s != null) ? s.engineKey : null;
452
+ boolean success = true;
453
+ Exception ex = null;
454
+ if (engineKey == null) {
455
+ if (callback != null)
456
+ callback.onComplete(false, null);
457
+ return;
458
+ }
459
+ LruResourceCache mc;
460
+ synchronized (this) {
461
+ mc = memoryCache;
462
+ }
463
+ if (mc == null) {
464
+ if (callback != null)
465
+ callback.onComplete(false, null);
466
+ return;
467
+ }
468
+ try {
469
+ mc.remove(engineKey);
470
+ } catch (Exception e) {
471
+ success = false;
472
+ ex = e;
473
+ }
474
+ if (callback != null)
475
+ callback.onComplete(success, ex);
476
+ }
477
+
478
+ /**
479
+ * Best-effort synchronous check whether the given id is currently present in
480
+ * the memory cache.
481
+ *
482
+ * - Returns true if present.
483
+ * - Returns false if not present or if we cannot determine (no suitable method
484
+ * on MemoryCache).
485
+ *
486
+ * Notes:
487
+ * - This uses a reflective 'contains(Key)' check if available on your
488
+ * MemoryCache implementation,
489
+ * else tries a reflective 'get(Key)' as a fallback. If neither exists we cannot
490
+ * reliably check
491
+ * without evicting; so we return false.
492
+ *
493
+ * - Call this on the main thread.
494
+ */
495
+ @MainThread
496
+ public boolean isInMemoryCache(final String id) {
497
+ final CacheKeyStore.StoredKeys s = (persistentStore != null) ? persistentStore.get(id) : inMemoryKeyStore.get(id);
498
+ if (s == null || s.engineKey == null)
499
+ return false;
500
+ final Key engineKey = s.engineKey;
501
+ LruResourceCache mc;
502
+ synchronized (this) {
503
+ mc = memoryCache;
504
+ }
505
+ if (mc == null)
506
+ return false;
507
+
508
+ return mc.contains(engineKey);
509
+ }
510
+
511
+ /**
512
+ * Async disk presence check. Runs on background thread; callback invoked on
513
+ * main thread with two booleans:
514
+ * onResult(sourcePresent, transformedPresent)
515
+ */
516
+ public void isInDiskCacheAsync(final String id, final DiskPresenceCallback callback) {
517
+ diskExecutor.execute(() -> {
518
+ boolean sourcePresent = false;
519
+ boolean transformedPresent = false;
520
+
521
+ final CacheKeyStore.StoredKeys s = (persistentStore != null) ? persistentStore.get(id) : inMemoryKeyStore.get(id);
522
+
523
+ DiskCache dc;
524
+ synchronized (EvictionManager.this) {
525
+ dc = diskCache;
526
+ }
527
+
528
+ if (dc == null) {
529
+ mainHandler.post(() -> callback.onResult(false, false));
530
+ return;
531
+ }
532
+
533
+ try {
534
+ if (s != null && s.sourceKey != null) {
535
+ sourcePresent = dc.get(s.sourceKey) != null;
536
+ byte[] transformationBytes = getTransformationBytesFromStoredKeys(s);
537
+ Key resourceKey = new RecreatedResourceKey(s.sourceKey, s.signature, s.width, s.height, transformationBytes,
538
+ s.decodedResourceClass, s.optionsKeyBytes);
539
+ transformedPresent = dc.get(resourceKey) != null;
540
+ } else {
541
+ // fallback: check ObjectKey(id) as source
542
+ Key fallback = new com.bumptech.glide.signature.ObjectKey(id);
543
+ sourcePresent = dc.get(fallback) != null;
544
+ }
545
+ } catch (Exception ignored) {
546
+ }
547
+
548
+ final boolean finalSource = sourcePresent;
549
+ final boolean finalTransformed = transformedPresent;
550
+ mainHandler.post(() -> callback.onResult(finalSource, finalTransformed));
551
+ });
552
+ }
553
+
554
+ /**
555
+ * Blocking disk presence check (dangerous on main thread). Call from background
556
+ * only.
557
+ * Returns array [sourcePresent, transformedPresent].
558
+ */
559
+ public boolean[] isInDiskCacheBlocking(final String id) {
560
+ final CacheKeyStore.StoredKeys s = (persistentStore != null) ? persistentStore.get(id) : inMemoryKeyStore.get(id);
561
+ DiskCache dc;
562
+ synchronized (EvictionManager.this) {
563
+ dc = diskCache;
564
+ }
565
+ boolean sourcePresent = false;
566
+ boolean transformedPresent = false;
567
+ if (dc == null)
568
+ return new boolean[] { false, false };
569
+ try {
570
+ if (s != null && s.sourceKey != null) {
571
+ sourcePresent = dc.get(s.sourceKey) != null;
572
+ Key resourceKey = new RecreatedResourceKey(s.sourceKey, s.signature, s.width, s.height,
573
+ getTransformationBytesFromStoredKeys(s), s.decodedResourceClass, s.optionsKeyBytes);
574
+ transformedPresent = dc.get(resourceKey) != null;
575
+ } else {
576
+ Key fallback = new com.bumptech.glide.signature.ObjectKey(id);
577
+ sourcePresent = dc.get(fallback) != null;
578
+ }
579
+ } catch (Exception ignored) {
580
+ }
581
+ return new boolean[] { sourcePresent, transformedPresent };
582
+ }
583
+
584
+ /**
585
+ * Helper used by the eviction methods to coordinate deletes + memory removal.
586
+ */
587
+ private void performEvictionTasks(
588
+ final Key sourceKey,
589
+ final Key signature,
590
+ final int width,
591
+ final int height,
592
+ final byte[] transformationKeyBytes,
593
+ final Class<?> decodedResourceClass,
594
+ final byte[] optionsKeyBytes,
595
+ final Key engineKey,
596
+ @Nullable final EvictionCallback callback) {
597
+
598
+ int tasks = 0;
599
+ if (sourceKey != null)
600
+ tasks++;
601
+ if (signature != null && sourceKey != null)
602
+ tasks++;
603
+ if (tasks == 0) {
604
+ // only memory removal possible
605
+ if (engineKey != null) {
606
+ mainHandler.post(() -> {
607
+ MemoryCache mc;
608
+ synchronized (EvictionManager.this) {
609
+ mc = memoryCache;
610
+ }
611
+ if (mc != null) {
612
+ try {
613
+ mc.remove(engineKey);
614
+ } catch (Exception ignored) {
615
+ }
616
+ }
617
+ if (callback != null)
618
+ callback.onComplete(true, null);
619
+ });
620
+ } else {
621
+ if (callback != null)
622
+ mainHandler.post(() -> callback.onComplete(true, null));
623
+ }
624
+ return;
625
+ }
626
+
627
+ final AtomicInteger remaining = new AtomicInteger(tasks);
628
+ final AtomicBoolean failed = new AtomicBoolean(false);
629
+ final AtomicReference<Exception> firstException = new AtomicReference<>(null);
630
+
631
+ // delete source bytes
632
+ if (sourceKey != null) {
633
+ diskExecutor.execute(() -> {
634
+ DiskCache dc;
635
+ synchronized (EvictionManager.this) {
636
+ dc = diskCache;
637
+ }
638
+ if (dc != null) {
639
+ try {
640
+ dc.delete(sourceKey);
641
+ } catch (Exception e) {
642
+ failed.set(true);
643
+ firstException.compareAndSet(null, e);
644
+ }
645
+ }
646
+ if (remaining.decrementAndGet() == 0) {
647
+ mainHandler.post(() -> {
648
+ if (engineKey != null) {
649
+ MemoryCache mc;
650
+ synchronized (EvictionManager.this) {
651
+ mc = memoryCache;
652
+ }
653
+ if (mc != null) {
654
+ try {
655
+ mc.remove(engineKey);
656
+ } catch (Exception ignored) {
657
+ }
658
+ }
659
+ }
660
+ if (callback != null)
661
+ callback.onComplete(!failed.get(), firstException.get());
662
+ });
663
+ }
664
+ });
665
+ }
666
+
667
+ // delete transformed resource
668
+ if (signature != null && sourceKey != null) {
669
+ diskExecutor.execute(() -> {
670
+ DiskCache dc;
671
+ synchronized (EvictionManager.this) {
672
+ dc = diskCache;
673
+ }
674
+ if (dc != null) {
675
+ try {
676
+ Key resourceKey = new RecreatedResourceKey(sourceKey, signature, width, height, transformationKeyBytes,
677
+ decodedResourceClass, optionsKeyBytes);
678
+ dc.delete(resourceKey);
679
+ } catch (Exception e) {
680
+ failed.set(true);
681
+ firstException.compareAndSet(null, e);
682
+ }
683
+ }
684
+ if (remaining.decrementAndGet() == 0) {
685
+ mainHandler.post(() -> {
686
+ if (engineKey != null) {
687
+ MemoryCache mc;
688
+ synchronized (EvictionManager.this) {
689
+ mc = memoryCache;
690
+ }
691
+ if (mc != null) {
692
+ try {
693
+ mc.remove(engineKey);
694
+ } catch (Exception ignored) {
695
+ }
696
+ }
697
+ }
698
+ if (callback != null)
699
+ callback.onComplete(!failed.get(), firstException.get());
700
+ });
701
+ }
702
+ });
703
+ }
704
+ }
705
+
706
+ @Nullable
707
+ private CacheKeyStore.StoredKeys readStoredKeysPreferPersistent(String id) {
708
+ if (persistentStore != null) {
709
+ CacheKeyStore.StoredKeys s = persistentStore.get(id);
710
+ if (s != null) {
711
+ // keep mirrored in-memory copy for engineKey augmentation
712
+ inMemoryKeyStore.put(id, s);
713
+ return s;
714
+ }
715
+ }
716
+ return inMemoryKeyStore.get(id);
717
+ }
718
+
719
+ @Nullable
720
+ private static byte[] getTransformationBytesFromStoredKeys(CacheKeyStore.StoredKeys s) {
721
+ if (s == null)
722
+ return null;
723
+ if (s.transformationKeyBytes != null)
724
+ return s.transformationKeyBytes;
725
+ if (s.transformation != null) {
726
+ try {
727
+ RecordingDigest rd = new RecordingDigest();
728
+ s.transformation.updateDiskCacheKey(rd);
729
+ return rd.digest();
730
+ } catch (Exception ignored) {
731
+ }
732
+ }
733
+ return null;
734
+ }
735
+ }