Java 类com.bumptech.glide.load.Key 实例源码
项目:GitHub
文件:ApplicationVersionSignature.java
private static Key obtainVersionSignature(Context context) {
PackageInfo pInfo = null;
try {
pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
// Should never happen.
e.printStackTrace();
}
final String versionCode;
if (pInfo != null) {
versionCode = String.valueOf(pInfo.versionCode);
} else {
versionCode = UUID.randomUUID().toString();
}
return new ObjectKey(versionCode);
}
项目:GitHub
文件:BitmapPreFillRunnerTest.java
@Test
public void testAddsBitmapsToPoolIfMemoryCacheIsNotFullButCannotFitBitmap() {
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
when(cache.getMaxSize()).thenReturn((long) Util.getBitmapByteSize(bitmap) / 2);
PreFillType size =
new PreFillType.Builder(bitmap.getWidth(), bitmap.getHeight()).setConfig(bitmap.getConfig())
.build();
Map<PreFillType, Integer> allocationOrder = new HashMap<>();
allocationOrder.put(size, 1);
getHandler(allocationOrder).run();
verify(cache, never()).put(any(Key.class), anyResource());
// TODO(b/20335397): This code was relying on Bitmap equality which Robolectric removed
//verify(pool).put(eq(bitmap));
//assertThat(addedBitmaps).containsExactly(bitmap);
}
项目:GitHub
文件:GlideTest.java
private static <X, Y> void registerMockModelLoader(Class<X> modelClass, Class<Y> dataClass,
Y loadedData, Registry registry) {
DataFetcher<Y> mockStreamFetcher = mock(DataFetcher.class);
when(mockStreamFetcher.getDataClass()).thenReturn(dataClass);
try {
doAnswer(new Util.CallDataReady<>(loadedData))
.when(mockStreamFetcher)
.loadData(isA(Priority.class), isA(DataFetcher.DataCallback.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
ModelLoader<X, Y> mockUrlLoader = mock(ModelLoader.class);
when(mockUrlLoader.buildLoadData(isA(modelClass), anyInt(), anyInt(), isA(Options.class)))
.thenReturn(new ModelLoader.LoadData<>(mock(Key.class), mockStreamFetcher));
when(mockUrlLoader.handles(isA(modelClass))).thenReturn(true);
ModelLoaderFactory<X, Y> mockUrlLoaderFactory = mock(ModelLoaderFactory.class);
when(mockUrlLoaderFactory.build(isA(MultiModelLoaderFactory.class)))
.thenReturn(mockUrlLoader);
registry.replace(modelClass, dataClass, mockUrlLoaderFactory);
}
项目:GitHub
文件:DecodeJob.java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
TraceCompat.endSection();
}
}
}
项目:GitHub
文件:DiskLruCacheWrapper.java
@Override
public File get(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Get: Obtained: " + safeKey + " for for Key: " + key);
}
File result = null;
try {
// It is possible that the there will be a put in between these two gets. If so that shouldn't
// be a problem because we will always put the same value at the same key so our input streams
// will still represent the same data.
final DiskLruCache.Value value = getDiskCache().get(safeKey);
if (value != null) {
result = value.getFile(0);
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to get from disk cache", e);
}
}
return result;
}
项目:GitHub
文件:DiskCacheWriteLocker.java
void release(Key key) {
WriteLock writeLock;
synchronized (this) {
writeLock = Preconditions.checkNotNull(locks.get(key));
if (writeLock.interestedThreads < 1) {
throw new IllegalStateException("Cannot release a lock that is not held"
+ ", key: " + key
+ ", interestedThreads: " + writeLock.interestedThreads);
}
writeLock.interestedThreads--;
if (writeLock.interestedThreads == 0) {
WriteLock removed = locks.remove(key);
if (!removed.equals(writeLock)) {
throw new IllegalStateException("Removed the wrong lock"
+ ", expected to remove: " + writeLock
+ ", but actually removed: " + removed
+ ", key: " + key);
}
writeLockPool.offer(removed);
}
}
writeLock.lock.unlock();
}
项目:GitHub
文件:DecodeHelper.java
List<Key> getCacheKeys() {
if (!isCacheKeysSet) {
isCacheKeysSet = true;
cacheKeys.clear();
List<LoadData<?>> loadData = getLoadData();
int size = loadData.size();
for (int i = 0; i < size; i++) {
LoadData<?> data = loadData.get(i);
if (!cacheKeys.contains(data.sourceKey)) {
cacheKeys.add(data.sourceKey);
}
for (int j = 0; j < data.alternateKeys.size(); j++) {
if (!cacheKeys.contains(data.alternateKeys.get(j))) {
cacheKeys.add(data.alternateKeys.get(j));
}
}
}
}
return cacheKeys;
}
项目:GitHub
文件:ApplicationVersionSignature.java
private static Key obtainVersionSignature(Context context) {
PackageInfo pInfo = null;
try {
pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
// Should never happen.
e.printStackTrace();
}
final String versionCode;
if (pInfo != null) {
versionCode = String.valueOf(pInfo.versionCode);
} else {
versionCode = UUID.randomUUID().toString();
}
return new ObjectKey(versionCode);
}
项目:GitHub
文件:MultiModelLoader.java
@Override
public LoadData<Data> buildLoadData(Model model, int width, int height,
Options options) {
Key sourceKey = null;
int size = modelLoaders.size();
List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
if (modelLoader.handles(model)) {
LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
if (loadData != null) {
sourceKey = loadData.sourceKey;
fetchers.add(loadData.fetcher);
}
}
}
return !fetchers.isEmpty()
? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool)) : null;
}
项目:GitHub
文件:GlideTest.java
@SuppressWarnings("unchecked")
private <T, Z> void registerFailFactory(Class<T> failModel, Class<Z> failResource)
throws Exception {
DataFetcher<Z> failFetcher = mock(DataFetcher.class);
doAnswer(new Util.CallDataReady<>(null))
.when(failFetcher)
.loadData(isA(Priority.class), isA(DataFetcher.DataCallback.class));
when(failFetcher.getDataClass()).thenReturn(failResource);
ModelLoader<T, Z> failLoader = mock(ModelLoader.class);
when(failLoader.buildLoadData(isA(failModel), anyInt(), anyInt(), isA(Options.class)))
.thenReturn(new ModelLoader.LoadData<>(mock(Key.class), failFetcher));
when(failLoader.handles(isA(failModel))).thenReturn(true);
ModelLoaderFactory<T, Z> failFactory = mock(ModelLoaderFactory.class);
when(failFactory.build(isA(MultiModelLoaderFactory.class))).thenReturn(failLoader);
Glide.get(getContext()).getRegistry().prepend(failModel, failResource, failFactory);
}
项目:GitHub
文件:BitmapPreFillRunnerTest.java
@Test
public void testAddsBitmapsToBitmapPoolIfMemoryCacheIsFull() {
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
when(cache.getMaxSize()).thenReturn(0);
PreFillType size =
new PreFillType.Builder(bitmap.getWidth(), bitmap.getHeight()).setConfig(bitmap.getConfig())
.build();
Map<PreFillType, Integer> allocationOrder = new HashMap<>();
allocationOrder.put(size, 1);
getHandler(allocationOrder).run();
verify(cache, never()).put(any(Key.class), anyResource());
// TODO(b/20335397): This code was relying on Bitmap equality which Robolectric removed
// verify(pool).put(eq(bitmap));
// assertThat(addedBitmaps).containsExactly(bitmap);
}
项目:GitHub
文件:BaseGlideUrlLoaderTest.java
@Test
public void testBuildsNewUrlIfNotPresentInCache() {
int width = 10;
int height = 11;
urlLoader.resultUrl = "fakeUrl";
when(wrapped.buildLoadData(any(GlideUrl.class), eq(width), eq(height), eq(options)))
.thenAnswer(new Answer<ModelLoader.LoadData<InputStream>>() {
@Override
public ModelLoader.LoadData<InputStream> answer(InvocationOnMock invocationOnMock)
throws Throwable {
GlideUrl glideUrl = (GlideUrl) invocationOnMock.getArguments()[0];
assertEquals(urlLoader.resultUrl, glideUrl.toStringUrl());
return new ModelLoader.LoadData<>(mock(Key.class), fetcher);
}
});
assertEquals(fetcher,
urlLoader.buildLoadData(new GlideUrl(urlLoader.resultUrl), width, height, options).fetcher);
}
项目:GitHub
文件:GlideTest.java
@SuppressWarnings("unchecked")
private <T, Z> void registerFailFactory(Class<T> failModel, Class<Z> failResource) {
DataFetcher<Z> failFetcher = mock(DataFetcher.class);
doAnswer(new Util.CallDataReady<>(null))
.when(failFetcher)
.loadData(isA(Priority.class), isA(DataFetcher.DataCallback.class));
when(failFetcher.getDataClass()).thenReturn(failResource);
ModelLoader<T, Z> failLoader = mock(ModelLoader.class);
when(failLoader.buildLoadData(isA(failModel), anyInt(), anyInt(), isA(Options.class)))
.thenReturn(new ModelLoader.LoadData<>(mock(Key.class), failFetcher));
when(failLoader.handles(isA(failModel))).thenReturn(true);
ModelLoaderFactory<T, Z> failFactory = mock(ModelLoaderFactory.class);
when(failFactory.build(isA(MultiModelLoaderFactory.class))).thenReturn(failLoader);
Glide.get(context).getRegistry().prepend(failModel, failResource, failFactory);
}
项目:GitHub
文件:ApplicationVersionSignature.java
/**
* Returns the signature {@link com.bumptech.glide.load.Key} for version code of the Application
* of the given Context.
*/
public static Key obtain(Context context) {
String packageName = context.getPackageName();
Key result = PACKAGE_NAME_TO_KEY.get(packageName);
if (result == null) {
Key toAdd = obtainVersionSignature(context);
result = PACKAGE_NAME_TO_KEY.putIfAbsent(packageName, toAdd);
// There wasn't a previous mapping, so toAdd is now the Key.
if (result == null) {
result = toAdd;
}
}
return result;
}
项目:GitHub
文件:BitmapPreFillRunnerTest.java
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
doAnswer(new AddBitmapPoolAnswer(addedBitmaps)).when(pool).put(any(Bitmap.class));
when(pool.getDirty(anyInt(), anyInt(), any(Bitmap.Config.class)))
.thenAnswer(new CreateBitmap());
when(cache.put(any(Key.class), anyResource()))
.thenAnswer(new AddBitmapCacheAnswer(addedBitmaps));
}
项目:GitHub
文件:KeyTester.java
private KeyTester addRegressionTestInternal(Key key, String expectedDigest) {
isUsedWithoutCallingTest = true;
String oldValue = regressionTests.put(key, expectedDigest);
if (oldValue != null) {
throw new IllegalArgumentException(
"Given multiple values for: " + key + " old: " + oldValue + " new: " + expectedDigest);
}
return this;
}
项目:GitHub
文件:GlideRequest.java
/**
* @see GlideOptions#signature(Key)
*/
@CheckResult
public GlideRequest<TranscodeType> signature(@NonNull Key arg0) {
if (getMutableOptions() instanceof GlideOptions) {
this.requestOptions = ((GlideOptions) getMutableOptions()).signature(arg0);
} else {
this.requestOptions = new GlideOptions().apply(this.requestOptions).signature(arg0);
}
return this;
}
项目:GitHub
文件:GlideRequest.java
/**
* @see GlideOptions#signature(Key)
*/
@CheckResult
public GlideRequest<TranscodeType> signature(@NonNull Key arg0) {
if (getMutableOptions() instanceof GlideOptions) {
this.requestOptions = ((GlideOptions) getMutableOptions()).signature(arg0);
} else {
this.requestOptions = new GlideOptions().apply(this.requestOptions).signature(arg0);
}
return this;
}
项目:GitHub
文件:DiskLruCacheWrapper.java
@Override
public void delete(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
try {
getDiskCache().remove(safeKey);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to delete from disk cache", e);
}
}
}
项目:GitHub
文件:LruResourceCacheTest.java
@Test
public void testPreventEviction() {
final MemoryCache cache = new LruResourceCache(100);
final Resource<?> first = getResource(30);
final Key firstKey = new MockKey();
cache.put(firstKey, first);
Resource<?> second = getResource(30);
Key secondKey = new MockKey();
cache.put(secondKey, second);
Resource<?> third = getResource(30);
Key thirdKey = new MockKey();
cache.put(thirdKey, third);
cache.setResourceRemovedListener(new ResourceRemovedListener() {
@Override
public void onResourceRemoved(Resource<?> removed) {
if (removed == first) {
cache.put(firstKey, first);
}
}
});
// trims from 100 to 50, having 30+30+30 items, it should trim to 1 item
cache.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
// and that 1 item must be first, because it's forced to return to cache in the listener
@SuppressWarnings("unchecked")
LruCache<Key, Resource<?>> lruCache = (LruCache<Key, Resource<?>>) cache;
assertTrue(lruCache.contains(firstKey));
assertFalse(lruCache.contains(secondKey));
assertFalse(lruCache.contains(thirdKey));
}
项目:GitHub
文件:DecodeJob.java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
decodeFromRetrievedData();
}
}
项目:GitHub
文件:DiskLruCacheWrapper.java
@Override
public void put(Key key, Writer writer) {
// We want to make sure that puts block so that data is available when put completes. We may
// actually not write any data if we find that data is written by the time we acquire the lock.
String safeKey = safeKeyGenerator.getSafeKey(key);
writeLocker.acquire(safeKey);
try {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Put: Obtained: " + safeKey + " for for Key: " + key);
}
try {
// We assume we only need to put once, so if data was written while we were trying to get
// the lock, we can simply abort.
DiskLruCache diskCache = getDiskCache();
Value current = diskCache.get(safeKey);
if (current != null) {
return;
}
DiskLruCache.Editor editor = diskCache.edit(safeKey);
if (editor == null) {
throw new IllegalStateException("Had two simultaneous puts for: " + safeKey);
}
try {
File file = editor.getFile(0);
if (writer.write(file)) {
editor.commit();
}
} finally {
editor.abortUnlessCommitted();
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to put to disk cache", e);
}
}
} finally {
writeLocker.release(safeKey);
}
}
项目:GitHub
文件:Engine.java
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
项目:GitHub
文件:Engine.java
@SuppressWarnings("unchecked")
private EngineResource<?> getEngineResourceFromCache(Key key) {
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result = new EngineResource<>(cached, true /*isMemoryCacheable*/);
}
return result;
}
项目:GitHub
文件:Engine.java
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
项目:GitHub
文件:EngineKeyFactory.java
@SuppressWarnings("rawtypes")
public EngineKey buildKey(Object model, Key signature, int width, int height,
Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass,
Class<?> transcodeClass, Options options) {
return new EngineKey(model, signature, width, height, transformations, resourceClass,
transcodeClass, options);
}
项目:GitHub
文件:SourceGenerator.java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
// This data fetcher will be loading from a File and provide the wrong data source, so override
// with the data source of the original fetcher
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
项目:GitHub
文件:DiskLruCacheWrapper.java
@Override
public void delete(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
try {
getDiskCache().remove(safeKey);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to delete from disk cache", e);
}
}
}
项目:GitHub
文件:EmptySignatureTest.java
@Test
public void testEquals() {
keyTester
.addEquivalenceGroup(
EmptySignature.obtain(),
EmptySignature.obtain())
.addEquivalenceGroup(mock(Key.class))
.addEmptyDigestRegressionTest(EmptySignature.obtain())
.test();
}
项目:GitHub
文件:GlideRequest.java
/**
* @see GlideOptions#signature(Key)
*/
@CheckResult
public GlideRequest<TranscodeType> signature(@NonNull Key arg0) {
if (getMutableOptions() instanceof GlideOptions) {
this.requestOptions = ((GlideOptions) getMutableOptions()).signature(arg0);
} else {
this.requestOptions = new GlideOptions().apply(this.requestOptions).signature(arg0);
}
return this;
}
项目:GitHub
文件:ActiveResources.java
@Synthetic
@SuppressWarnings("WeakerAccess")
ResourceWeakReference(
Key key, EngineResource<?> r, ReferenceQueue<? super EngineResource<?>> q) {
super(r, q);
this.key = Preconditions.checkNotNull(key);
this.resource = Preconditions.checkNotNull(r.getResource());
isCacheable = r.isCacheable();
}
项目:GitHub
文件:GlideRequest.java
/**
* @see GlideOptions#signature(Key)
*/
@CheckResult
public GlideRequest<TranscodeType> signature(@NonNull Key arg0) {
if (getMutableOptions() instanceof GlideOptions) {
this.requestOptions = ((GlideOptions) getMutableOptions()).signature(arg0);
} else {
this.requestOptions = new GlideOptions().apply(this.requestOptions).signature(arg0);
}
return this;
}
项目:GitHub
文件:SourceGenerator.java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
// This data fetcher will be loading from a File and provide the wrong data source, so override
// with the data source of the original fetcher
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
项目:PeSanKita-android
文件:RecentPhotoViewRail.java
@Override
public void onBindItemViewHolder(RecentPhotoViewHolder viewHolder, @NonNull Cursor cursor) {
viewHolder.imageView.setImageDrawable(null);
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
long dateTaken = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_MODIFIED));
String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.MIME_TYPE));
int orientation = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION));
final Uri uri = Uri.withAppendedPath(baseUri, Long.toString(id));
Key signature = new MediaStoreSignature(mimeType, dateModified, orientation);
Glide.with(getContext())
.fromMediaStore()
.load(uri)
.signature(signature)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(viewHolder.imageView);
viewHolder.imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (clickedListener != null) clickedListener.onItemClicked(uri);
}
});
}
项目:GitHub
文件:BaseGlideUrlLoader.java
private static List<Key> getAlternateKeys(List<String> alternateUrls) {
List<Key> result = new ArrayList<>(alternateUrls.size());
for (String alternate : alternateUrls) {
result.add(new GlideUrl(alternate));
}
return result;
}
项目:GitHub
文件:GlideRequest.java
/**
* @see GlideOptions#signature(Key)
*/
@CheckResult
public GlideRequest<TranscodeType> signature(@NonNull Key arg0) {
if (getMutableOptions() instanceof GlideOptions) {
this.requestOptions = ((GlideOptions) getMutableOptions()).signature(arg0);
} else {
this.requestOptions = new GlideOptions().apply(this.requestOptions).signature(arg0);
}
return this;
}
项目:GitHub
文件:KeyTester.java
private byte[] getDigest(Key key) {
try {
key.updateDiskCacheKey(digest);
return digest.digest();
} finally {
digest.reset();
}
}
项目:GitHub
文件:BaseGlideUrlLoaderTest.java
@Test
public void testReturnsUrlFromCacheIfPresent() {
Object model = new Object();
int width = 100;
int height = 200;
GlideUrl expectedUrl = mock(GlideUrl.class);
when(modelCache.get(eq(model), eq(width), eq(height))).thenReturn(expectedUrl);
when(wrapped.buildLoadData(eq(expectedUrl), eq(width), eq(height), eq(options)))
.thenReturn(new ModelLoader.LoadData<>(mock(Key.class), fetcher));
assertEquals(
fetcher,
Preconditions.checkNotNull(urlLoader.buildLoadData(model, width, height, options)).fetcher);
}
项目:GitHub
文件:RecyclerAdapter.java
@Override
public void onBindViewHolder(ListViewHolder viewHolder, int position) {
MediaStoreData current = data.get(position);
Key signature =
new MediaStoreSignature(current.mimeType, current.dateModified, current.orientation);
requestBuilder
.clone()
.signature(signature)
.load(current.uri)
.into(viewHolder.image);
}
项目:GitHub
文件:ApplicationVersionSignature.java
/**
* Returns the signature {@link com.bumptech.glide.load.Key} for version code of the Application
* of the given Context.
*/
public static Key obtain(Context context) {
String packageName = context.getPackageName();
Key result = PACKAGE_NAME_TO_KEY.get(packageName);
if (result == null) {
Key toAdd = obtainVersionSignature(context);
result = PACKAGE_NAME_TO_KEY.putIfAbsent(packageName, toAdd);
// There wasn't a previous mapping, so toAdd is now the Key.
if (result == null) {
result = toAdd;
}
}
return result;
}