Add NonNull annotations to upstream.cache and upstream.crypto

PiperOrigin-RevId: 284548019
This commit is contained in:
olly 2019-12-09 15:22:11 +00:00 committed by Oliver Woodman
parent 0b7f93a5d4
commit c90c10c981
14 changed files with 97 additions and 52 deletions

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream.cache; package com.google.android.exoplayer2.upstream.cache;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSink; import com.google.android.exoplayer2.upstream.DataSink;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
@ -27,6 +28,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Writes data into a cache. * Writes data into a cache.
@ -49,13 +51,13 @@ public final class CacheDataSink implements DataSink {
private final long fragmentSize; private final long fragmentSize;
private final int bufferSize; private final int bufferSize;
private DataSpec dataSpec; @Nullable private DataSpec dataSpec;
private long dataSpecFragmentSize; private long dataSpecFragmentSize;
private File file; @Nullable private File file;
private OutputStream outputStream; @Nullable private OutputStream outputStream;
private long outputStreamBytesWritten; private long outputStreamBytesWritten;
private long dataSpecBytesWritten; private long dataSpecBytesWritten;
private ReusableBufferedOutputStream bufferedOutputStream; @MonotonicNonNull private ReusableBufferedOutputStream bufferedOutputStream;
/** /**
* Thrown when IOException is encountered when writing data into sink. * Thrown when IOException is encountered when writing data into sink.

View File

@ -377,7 +377,7 @@ public final class CacheDataSource implements DataSource {
* reading from {@link #upstreamDataSource}, which is the currently open source. * reading from {@link #upstreamDataSource}, which is the currently open source.
*/ */
private void openNextSource(boolean checkCache) throws IOException { private void openNextSource(boolean checkCache) throws IOException {
CacheSpan nextSpan; @Nullable CacheSpan nextSpan;
if (currentRequestIgnoresCache) { if (currentRequestIgnoresCache) {
nextSpan = null; nextSpan = null;
} else if (blockOnCache) { } else if (blockOnCache) {
@ -487,7 +487,7 @@ public final class CacheDataSource implements DataSource {
} }
private static Uri getRedirectedUriOrDefault(Cache cache, String key, Uri defaultUri) { private static Uri getRedirectedUriOrDefault(Cache cache, String key, Uri defaultUri) {
Uri redirectedUri = ContentMetadata.getRedirectedUri(cache.getContentMetadata(key)); @Nullable Uri redirectedUri = ContentMetadata.getRedirectedUri(cache.getContentMetadata(key));
return redirectedUri != null ? redirectedUri : defaultUri; return redirectedUri != null ? redirectedUri : defaultUri;
} }

View File

@ -60,7 +60,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final DatabaseProvider databaseProvider; private final DatabaseProvider databaseProvider;
private @MonotonicNonNull String tableName; @MonotonicNonNull private String tableName;
/** /**
* Deletes index data for the specified cache. * Deletes index data for the specified cache.

View File

@ -24,6 +24,7 @@ public interface CacheKeyFactory {
* Returns a cache key for the given {@link DataSpec}. * Returns a cache key for the given {@link DataSpec}.
* *
* @param dataSpec The data being cached. * @param dataSpec The data being cached.
* @return The cache key.
*/ */
String buildCacheKey(DataSpec dataSpec); String buildCacheKey(DataSpec dataSpec);
} }

View File

@ -183,7 +183,7 @@ public final class CacheUtil {
String key = buildCacheKey(dataSpec, cacheKeyFactory); String key = buildCacheKey(dataSpec, cacheKeyFactory);
long bytesLeft; long bytesLeft;
ProgressNotifier progressNotifier = null; @Nullable ProgressNotifier progressNotifier = null;
if (progressListener != null) { if (progressListener != null) {
progressNotifier = new ProgressNotifier(progressListener); progressNotifier = new ProgressNotifier(progressListener);
Pair<Long, Long> lengthAndBytesAlreadyCached = getCached(dataSpec, cache, cacheKeyFactory); Pair<Long, Long> lengthAndBytesAlreadyCached = getCached(dataSpec, cache, cacheKeyFactory);
@ -373,7 +373,7 @@ public final class CacheUtil {
} }
/* package */ static boolean isCausedByPositionOutOfRange(IOException e) { /* package */ static boolean isCausedByPositionOutOfRange(IOException e) {
Throwable cause = e; @Nullable Throwable cause = e;
while (cause != null) { while (cause != null) {
if (cause instanceof DataSourceException) { if (cause instanceof DataSourceException) {
int reason = ((DataSourceException) cause).reason; int reason = ((DataSourceException) cause).reason;

View File

@ -229,11 +229,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* @return A new or existing CachedContent instance with the given key. * @return A new or existing CachedContent instance with the given key.
*/ */
public CachedContent getOrAdd(String key) { public CachedContent getOrAdd(String key) {
CachedContent cachedContent = keyToContent.get(key); @Nullable CachedContent cachedContent = keyToContent.get(key);
return cachedContent == null ? addNew(key) : cachedContent; return cachedContent == null ? addNew(key) : cachedContent;
} }
/** Returns a CachedContent instance with the given key or null if there isn't one. */ /** Returns a CachedContent instance with the given key or null if there isn't one. */
@Nullable
public CachedContent get(String key) { public CachedContent get(String key) {
return keyToContent.get(key); return keyToContent.get(key);
} }
@ -254,14 +255,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
return getOrAdd(key).id; return getOrAdd(key).id;
} }
/** Returns the key which has the given id assigned. */ /** Returns the key which has the given id assigned, or {@code null} if no such key exists. */
@Nullable
public String getKeyForId(int id) { public String getKeyForId(int id) {
return idToKey.get(id); return idToKey.get(id);
} }
/** Removes {@link CachedContent} with the given key from index if it's empty and not locked. */ /** Removes {@link CachedContent} with the given key from index if it's empty and not locked. */
public void maybeRemove(String key) { public void maybeRemove(String key) {
CachedContent cachedContent = keyToContent.get(key); @Nullable CachedContent cachedContent = keyToContent.get(key);
if (cachedContent != null && cachedContent.isEmpty() && !cachedContent.isLocked()) { if (cachedContent != null && cachedContent.isEmpty() && !cachedContent.isLocked()) {
keyToContent.remove(key); keyToContent.remove(key);
int id = cachedContent.id; int id = cachedContent.id;
@ -626,7 +628,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
} }
private void writeFile(HashMap<String, CachedContent> content) throws IOException { private void writeFile(HashMap<String, CachedContent> content) throws IOException {
DataOutputStream output = null; @Nullable DataOutputStream output = null;
try { try {
OutputStream outputStream = atomicFile.startWrite(); OutputStream outputStream = atomicFile.startWrite();
if (bufferedOutputStream == null) { if (bufferedOutputStream == null) {

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.cache; package com.google.android.exoplayer2.upstream.cache;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -77,7 +78,7 @@ public final class CachedRegionTracker implements Cache.Listener {
*/ */
public synchronized int getRegionEndTimeMs(long byteOffset) { public synchronized int getRegionEndTimeMs(long byteOffset) {
lookupRegion.startOffset = byteOffset; lookupRegion.startOffset = byteOffset;
Region floorRegion = regions.floor(lookupRegion); @Nullable Region floorRegion = regions.floor(lookupRegion);
if (floorRegion == null || byteOffset > floorRegion.endOffset if (floorRegion == null || byteOffset > floorRegion.endOffset
|| floorRegion.endOffsetIndex == -1) { || floorRegion.endOffsetIndex == -1) {
return NOT_CACHED; return NOT_CACHED;
@ -102,7 +103,7 @@ public final class CachedRegionTracker implements Cache.Listener {
Region removedRegion = new Region(span.position, span.position + span.length); Region removedRegion = new Region(span.position, span.position + span.length);
// Look up a region this span falls into. // Look up a region this span falls into.
Region floorRegion = regions.floor(removedRegion); @Nullable Region floorRegion = regions.floor(removedRegion);
if (floorRegion == null) { if (floorRegion == null) {
Log.e(TAG, "Removed a span we were not aware of"); Log.e(TAG, "Removed a span we were not aware of");
return; return;
@ -134,8 +135,8 @@ public final class CachedRegionTracker implements Cache.Listener {
private void mergeSpan(CacheSpan span) { private void mergeSpan(CacheSpan span) {
Region newRegion = new Region(span.position, span.position + span.length); Region newRegion = new Region(span.position, span.position + span.length);
Region floorRegion = regions.floor(newRegion); @Nullable Region floorRegion = regions.floor(newRegion);
Region ceilingRegion = regions.ceiling(newRegion); @Nullable Region ceilingRegion = regions.ceiling(newRegion);
boolean floorConnects = regionsConnect(floorRegion, newRegion); boolean floorConnects = regionsConnect(floorRegion, newRegion);
boolean ceilingConnects = regionsConnect(newRegion, ceilingRegion); boolean ceilingConnects = regionsConnect(newRegion, ceilingRegion);
@ -168,7 +169,7 @@ public final class CachedRegionTracker implements Cache.Listener {
} }
} }
private boolean regionsConnect(Region lower, Region upper) { private boolean regionsConnect(@Nullable Region lower, @Nullable Region upper) {
return lower != null && upper != null && lower.endOffset == upper.startOffset; return lower != null && upper != null && lower.endOffset == upper.startOffset;
} }

View File

@ -81,7 +81,7 @@ public interface ContentMetadata {
*/ */
@Nullable @Nullable
static Uri getRedirectedUri(ContentMetadata contentMetadata) { static Uri getRedirectedUri(ContentMetadata contentMetadata) {
String redirectedUri = contentMetadata.get(KEY_REDIRECTED_URI, (String) null); @Nullable String redirectedUri = contentMetadata.get(KEY_REDIRECTED_URI, (String) null);
return redirectedUri == null ? null : Uri.parse(redirectedUri); return redirectedUri == null ? null : Uri.parse(redirectedUri);
} }
} }

View File

@ -73,8 +73,7 @@ public class ContentMetadataMutations {
} }
/** /**
* Adds a mutation to set a metadata value. Passing {@code null} as {@code name} or {@code value} * Adds a mutation to set a metadata value.
* isn't allowed.
* *
* @param name The name of the metadata value. * @param name The name of the metadata value.
* @param value The value to be set. * @param value The value to be set.
@ -85,7 +84,7 @@ public class ContentMetadataMutations {
} }
/** /**
* Adds a mutation to set a metadata value. Passing {@code null} as {@code name} isn't allowed. * Adds a mutation to set a metadata value.
* *
* @param name The name of the metadata value. * @param name The name of the metadata value.
* @param value The value to be set. * @param value The value to be set.
@ -96,8 +95,7 @@ public class ContentMetadataMutations {
} }
/** /**
* Adds a mutation to set a metadata value. Passing {@code null} as {@code name} or {@code value} * Adds a mutation to set a metadata value.
* isn't allowed.
* *
* @param name The name of the metadata value. * @param name The name of the metadata value.
* @param value The value to be set. * @param value The value to be set.

View File

@ -67,8 +67,8 @@ public final class DefaultContentMetadata implements ContentMetadata {
@Override @Override
@Nullable @Nullable
public final byte[] get(String name, @Nullable byte[] defaultValue) { public final byte[] get(String name, @Nullable byte[] defaultValue) {
if (metadata.containsKey(name)) { @Nullable byte[] bytes = metadata.get(name);
byte[] bytes = metadata.get(name); if (bytes != null) {
return Arrays.copyOf(bytes, bytes.length); return Arrays.copyOf(bytes, bytes.length);
} else { } else {
return defaultValue; return defaultValue;
@ -78,8 +78,8 @@ public final class DefaultContentMetadata implements ContentMetadata {
@Override @Override
@Nullable @Nullable
public final String get(String name, @Nullable String defaultValue) { public final String get(String name, @Nullable String defaultValue) {
if (metadata.containsKey(name)) { @Nullable byte[] bytes = metadata.get(name);
byte[] bytes = metadata.get(name); if (bytes != null) {
return new String(bytes, Charset.forName(C.UTF8_NAME)); return new String(bytes, Charset.forName(C.UTF8_NAME));
} else { } else {
return defaultValue; return defaultValue;
@ -88,8 +88,8 @@ public final class DefaultContentMetadata implements ContentMetadata {
@Override @Override
public final long get(String name, long defaultValue) { public final long get(String name, long defaultValue) {
if (metadata.containsKey(name)) { @Nullable byte[] bytes = metadata.get(name);
byte[] bytes = metadata.get(name); if (bytes != null) {
return ByteBuffer.wrap(bytes).getLong(); return ByteBuffer.wrap(bytes).getLong();
} else { } else {
return defaultValue; return defaultValue;
@ -130,7 +130,7 @@ public final class DefaultContentMetadata implements ContentMetadata {
} }
for (Entry<String, byte[]> entry : first.entrySet()) { for (Entry<String, byte[]> entry : first.entrySet()) {
byte[] value = entry.getValue(); byte[] value = entry.getValue();
byte[] otherValue = second.get(entry.getKey()); @Nullable byte[] otherValue = second.get(entry.getKey());
if (!Arrays.equals(value, otherValue)) { if (!Arrays.equals(value, otherValue)) {
return false; return false;
} }
@ -153,8 +153,8 @@ public final class DefaultContentMetadata implements ContentMetadata {
} }
private static void addValues(HashMap<String, byte[]> metadata, Map<String, Object> values) { private static void addValues(HashMap<String, byte[]> metadata, Map<String, Object> values) {
for (String name : values.keySet()) { for (Entry<String, Object> entry : values.entrySet()) {
metadata.put(name, getBytes(values.get(name))); metadata.put(entry.getKey(), getBytes(entry.getValue()));
} }
} }

View File

@ -465,8 +465,7 @@ public final class SimpleCache implements Cache {
@Override @Override
public synchronized void releaseHoleSpan(CacheSpan holeSpan) { public synchronized void releaseHoleSpan(CacheSpan holeSpan) {
Assertions.checkState(!released); Assertions.checkState(!released);
CachedContent cachedContent = contentIndex.get(holeSpan.key); CachedContent cachedContent = Assertions.checkNotNull(contentIndex.get(holeSpan.key));
Assertions.checkNotNull(cachedContent);
Assertions.checkState(cachedContent.isLocked()); Assertions.checkState(cachedContent.isLocked());
cachedContent.setLocked(false); cachedContent.setLocked(false);
contentIndex.maybeRemove(cachedContent.key); contentIndex.maybeRemove(cachedContent.key);
@ -482,14 +481,14 @@ public final class SimpleCache implements Cache {
@Override @Override
public synchronized boolean isCached(String key, long position, long length) { public synchronized boolean isCached(String key, long position, long length) {
Assertions.checkState(!released); Assertions.checkState(!released);
CachedContent cachedContent = contentIndex.get(key); @Nullable CachedContent cachedContent = contentIndex.get(key);
return cachedContent != null && cachedContent.getCachedBytesLength(position, length) >= length; return cachedContent != null && cachedContent.getCachedBytesLength(position, length) >= length;
} }
@Override @Override
public synchronized long getCachedLength(String key, long position, long length) { public synchronized long getCachedLength(String key, long position, long length) {
Assertions.checkState(!released); Assertions.checkState(!released);
CachedContent cachedContent = contentIndex.get(key); @Nullable CachedContent cachedContent = contentIndex.get(key);
return cachedContent != null ? cachedContent.getCachedBytesLength(position, length) : -length; return cachedContent != null ? cachedContent.getCachedBytesLength(position, length) : -length;
} }
@ -524,7 +523,7 @@ public final class SimpleCache implements Cache {
} }
} }
File[] files = cacheDir.listFiles(); @Nullable File[] files = cacheDir.listFiles();
if (files == null) { if (files == null) {
String message = "Failed to list cache directory files: " + cacheDir; String message = "Failed to list cache directory files: " + cacheDir;
Log.e(TAG, message); Log.e(TAG, message);
@ -605,11 +604,13 @@ public final class SimpleCache implements Cache {
} }
long length = C.LENGTH_UNSET; long length = C.LENGTH_UNSET;
long lastTouchTimestamp = C.TIME_UNSET; long lastTouchTimestamp = C.TIME_UNSET;
@Nullable
CacheFileMetadata metadata = fileMetadata != null ? fileMetadata.remove(fileName) : null; CacheFileMetadata metadata = fileMetadata != null ? fileMetadata.remove(fileName) : null;
if (metadata != null) { if (metadata != null) {
length = metadata.length; length = metadata.length;
lastTouchTimestamp = metadata.lastTouchTimestamp; lastTouchTimestamp = metadata.lastTouchTimestamp;
} }
@Nullable
SimpleCacheSpan span = SimpleCacheSpan span =
SimpleCacheSpan.createCacheEntry(file, length, lastTouchTimestamp, contentIndex); SimpleCacheSpan.createCacheEntry(file, length, lastTouchTimestamp, contentIndex);
if (span != null) { if (span != null) {
@ -666,7 +667,7 @@ public final class SimpleCache implements Cache {
* @return The corresponding cache {@link SimpleCacheSpan}. * @return The corresponding cache {@link SimpleCacheSpan}.
*/ */
private SimpleCacheSpan getSpan(String key, long position) { private SimpleCacheSpan getSpan(String key, long position) {
CachedContent cachedContent = contentIndex.get(key); @Nullable CachedContent cachedContent = contentIndex.get(key);
if (cachedContent == null) { if (cachedContent == null) {
return SimpleCacheSpan.createOpenHole(key, position); return SimpleCacheSpan.createOpenHole(key, position);
} }
@ -694,7 +695,7 @@ public final class SimpleCache implements Cache {
} }
private void removeSpanInternal(CacheSpan span) { private void removeSpanInternal(CacheSpan span) {
CachedContent cachedContent = contentIndex.get(span.key); @Nullable CachedContent cachedContent = contentIndex.get(span.key);
if (cachedContent == null || !cachedContent.removeSpan(span)) { if (cachedContent == null || !cachedContent.removeSpan(span)) {
return; return;
} }
@ -732,7 +733,7 @@ public final class SimpleCache implements Cache {
} }
private void notifySpanRemoved(CacheSpan span) { private void notifySpanRemoved(CacheSpan span) {
ArrayList<Listener> keyListeners = listeners.get(span.key); @Nullable ArrayList<Listener> keyListeners = listeners.get(span.key);
if (keyListeners != null) { if (keyListeners != null) {
for (int i = keyListeners.size() - 1; i >= 0; i--) { for (int i = keyListeners.size() - 1; i >= 0; i--) {
keyListeners.get(i).onSpanRemoved(this, span); keyListeners.get(i).onSpanRemoved(this, span);
@ -742,7 +743,7 @@ public final class SimpleCache implements Cache {
} }
private void notifySpanAdded(SimpleCacheSpan span) { private void notifySpanAdded(SimpleCacheSpan span) {
ArrayList<Listener> keyListeners = listeners.get(span.key); @Nullable ArrayList<Listener> keyListeners = listeners.get(span.key);
if (keyListeners != null) { if (keyListeners != null) {
for (int i = keyListeners.size() - 1; i >= 0; i--) { for (int i = keyListeners.size() - 1; i >= 0; i--) {
keyListeners.get(i).onSpanAdded(this, span); keyListeners.get(i).onSpanAdded(this, span);
@ -752,7 +753,7 @@ public final class SimpleCache implements Cache {
} }
private void notifySpanTouched(SimpleCacheSpan oldSpan, CacheSpan newSpan) { private void notifySpanTouched(SimpleCacheSpan oldSpan, CacheSpan newSpan) {
ArrayList<Listener> keyListeners = listeners.get(oldSpan.key); @Nullable ArrayList<Listener> keyListeners = listeners.get(oldSpan.key);
if (keyListeners != null) { if (keyListeners != null) {
for (int i = keyListeners.size() - 1; i >= 0; i--) { for (int i = keyListeners.size() - 1; i >= 0; i--) {
keyListeners.get(i).onSpanTouched(this, oldSpan, newSpan); keyListeners.get(i).onSpanTouched(this, oldSpan, newSpan);

View File

@ -91,6 +91,7 @@ import java.util.regex.Pattern;
* @param length The length of the cache file in bytes, or {@link C#LENGTH_UNSET} to query the * @param length The length of the cache file in bytes, or {@link C#LENGTH_UNSET} to query the
* underlying file system. Querying the underlying file system can be expensive, so callers * underlying file system. Querying the underlying file system can be expensive, so callers
* that already know the length of the file should pass it explicitly. * that already know the length of the file should pass it explicitly.
* @param index The cached content index.
* @return The span, or null if the file name is not correctly formatted, or if the id is not * @return The span, or null if the file name is not correctly formatted, or if the id is not
* present in the content index, or if the length is 0. * present in the content index, or if the length is 0.
*/ */
@ -108,6 +109,7 @@ import java.util.regex.Pattern;
* that already know the length of the file should pass it explicitly. * that already know the length of the file should pass it explicitly.
* @param lastTouchTimestamp The last touch timestamp, or {@link C#TIME_UNSET} to use the file * @param lastTouchTimestamp The last touch timestamp, or {@link C#TIME_UNSET} to use the file
* timestamp. * timestamp.
* @param index The cached content index.
* @return The span, or null if the file name is not correctly formatted, or if the id is not * @return The span, or null if the file name is not correctly formatted, or if the id is not
* present in the content index, or if the length is 0. * present in the content index, or if the length is 0.
*/ */
@ -130,7 +132,7 @@ import java.util.regex.Pattern;
} }
int id = Integer.parseInt(matcher.group(1)); int id = Integer.parseInt(matcher.group(1));
String key = index.getKeyForId(id); @Nullable String key = index.getKeyForId(id);
if (key == null) { if (key == null) {
return null; return null;
} }
@ -153,26 +155,26 @@ import java.util.regex.Pattern;
* Upgrades the cache file if it is created by an earlier version of {@link SimpleCache}. * Upgrades the cache file if it is created by an earlier version of {@link SimpleCache}.
* *
* @param file The cache file. * @param file The cache file.
* @param index Cached content index. * @param index The cached content index.
* @return Upgraded cache file or {@code null} if the file name is not correctly formatted or the * @return Upgraded cache file or {@code null} if the file name is not correctly formatted or the
* file can not be renamed. * file can not be renamed.
*/ */
@Nullable @Nullable
private static File upgradeFile(File file, CachedContentIndex index) { private static File upgradeFile(File file, CachedContentIndex index) {
String key; @Nullable String key = null;
String filename = file.getName(); String filename = file.getName();
Matcher matcher = CACHE_FILE_PATTERN_V2.matcher(filename); Matcher matcher = CACHE_FILE_PATTERN_V2.matcher(filename);
if (matcher.matches()) { if (matcher.matches()) {
key = Util.unescapeFileName(matcher.group(1)); key = Util.unescapeFileName(matcher.group(1));
if (key == null) {
return null;
}
} else { } else {
matcher = CACHE_FILE_PATTERN_V1.matcher(filename); matcher = CACHE_FILE_PATTERN_V1.matcher(filename);
if (!matcher.matches()) { if (matcher.matches()) {
return null; key = matcher.group(1); // Keys were not escaped in version 1.
} }
key = matcher.group(1); // Keys were not escaped in version 1. }
if (key == null) {
return null;
} }
File newCacheFile = File newCacheFile =

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.upstream.cache;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.upstream.crypto;
import com.google.android.exoplayer2.util.NonNullApi;