@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.
- package/CHANGELOG.md +7 -0
- package/README.md +4 -20
- package/index-common.d.ts +47 -18
- package/index-common.js +5 -69
- package/index-common.js.map +1 -1
- package/index.android.d.ts +33 -60
- package/index.android.js +597 -702
- package/index.android.js.map +1 -1
- package/index.d.ts +17 -92
- package/index.ios.d.ts +5 -10
- package/index.ios.js +72 -54
- package/index.ios.js.map +1 -1
- package/package.json +4 -4
- package/platforms/android/include.gradle +21 -16
- package/platforms/android/java/com/nativescript/image/CacheKeyStore.java +65 -0
- package/platforms/android/java/com/nativescript/image/CapturingEngineKeyFactory.java +43 -0
- package/platforms/android/java/com/nativescript/image/CompositeRequestListener.java +58 -0
- package/platforms/android/java/com/nativescript/image/ConditionalCrossFadeFactory.java +33 -0
- package/platforms/android/java/com/nativescript/image/CustomDataFetcher.java +124 -0
- package/platforms/android/java/com/nativescript/image/CustomGlideModule.java +220 -0
- package/platforms/android/java/com/nativescript/image/CustomGlideUrl.java +52 -0
- package/platforms/android/java/com/nativescript/image/CustomUrlLoader.java +74 -0
- package/platforms/android/java/com/nativescript/image/EvictionManager.java +735 -0
- package/platforms/android/java/com/nativescript/image/ExtractRequestOptions.java +109 -0
- package/platforms/android/java/com/nativescript/image/ImageLoadSourceCallback.java +5 -0
- package/platforms/android/java/com/nativescript/image/ImageProgressCallback.java +5 -0
- package/platforms/android/java/com/nativescript/image/LoadSourceInterceptor.java +28 -0
- package/platforms/android/java/com/nativescript/image/MatrixDrawable.java +200 -0
- package/platforms/android/java/com/nativescript/image/MatrixDrawableImageViewTarget.java +154 -0
- package/platforms/android/java/com/nativescript/image/MatrixImageView.java +696 -0
- package/platforms/android/java/com/nativescript/image/ProgressInterceptor.java +25 -0
- package/platforms/android/java/com/nativescript/image/ProgressResponseBody.java +70 -0
- package/platforms/android/java/com/nativescript/image/RecordingDigest.java +48 -0
- package/platforms/android/java/com/nativescript/image/RecreatedResourceKey.java +95 -0
- package/platforms/android/java/com/nativescript/image/SaveKeysRequestListener.java +145 -0
- package/platforms/android/java/com/nativescript/image/ScaleUtils.java +129 -0
- package/platforms/android/java/com/nativescript/image/SharedPrefCacheKeyStore.java +92 -0
- package/platforms/android/native-api-usage.json +39 -37
- package/platforms/ios/Podfile +1 -1
- package/references.d.ts +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/typings/android.d.ts +4 -27
- package/typings/glide.android.d.ts +9395 -0
- package/typings/glide.okhttp.android.d.ts +104 -0
- package/typings/glide.transform.android.d.ts +540 -0
- package/typings/ui_image.android.d.ts +517 -0
- package/platforms/android/java/com/nativescript/image/BaseDataSubscriber.java +0 -22
- package/platforms/android/java/com/nativescript/image/BaseDataSubscriberListener.java +0 -9
- package/platforms/android/java/com/nativescript/image/DraweeView.java +0 -371
- package/platforms/android/java/com/nativescript/image/NetworkImageRequest.java +0 -55
- package/platforms/android/java/com/nativescript/image/OkHttpNetworkFetcher.java +0 -56
- package/platforms/android/java/com/nativescript/image/ScalingBlurPostprocessor.java +0 -64
- package/platforms/android/java/com/nativescript/image/ScalingUtils.java +0 -519
- package/typings/fresco-processors.d.ts +0 -53
- 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
|
+
}
|