diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadata.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java similarity index 71% rename from library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadata.java rename to library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java index c6df798c54..f35b29db14 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadata.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadata.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.upstream.cache; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; import com.google.android.exoplayer2.util.Assertions; @@ -25,20 +26,45 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -/** Abstract implementation of {@link ContentMetadata}. Values are stored as byte arrays. */ -public abstract class AbstractContentMetadata implements ContentMetadata { +/** Default implementation of {@link ContentMetadata}. Values are stored as byte arrays. */ +public final class DefaultContentMetadata implements ContentMetadata { + + /** Listener for metadata change event. */ + public interface ChangeListener { + /** + * Called when any metadata value is changed or removed. + * + * @param contentMetadata The reporting instance. + * @param metadataValues All metadata name, value pairs. It shouldn't be accessed out of this + * method. + */ + void onChange(DefaultContentMetadata contentMetadata, Map metadataValues) + throws CacheException; + } private final Map metadata; + @Nullable private ChangeListener changeListener; - protected AbstractContentMetadata() { + public DefaultContentMetadata() { this.metadata = new HashMap<>(); } - /** @param metadata Initial name value pairs. */ - protected AbstractContentMetadata(Map metadata) { + /** + * Constructs a {@link DefaultContentMetadata} using name, value pairs data which was passed to + * {@link ChangeListener#onChange(DefaultContentMetadata, Map)}. + * + * @param metadata Initial name, value pairs. + */ + public DefaultContentMetadata(Map metadata) { this.metadata = new HashMap<>(metadata); } + /** Sets a {@link ChangeListener}. This method can be called once. */ + public void setChangeListener(ChangeListener changeListener) { + Assertions.checkState(this.changeListener == null); + this.changeListener = Assertions.checkNotNull(changeListener); + } + @Override public final Editor edit() { return new EditorImpl(); @@ -86,14 +112,6 @@ public abstract class AbstractContentMetadata implements ContentMetadata { } } - /** - * Called when any metadata value is changed or removed. {@code metadataValues} shouldn't be - * accessed out of this method. - * - * @param metadataValues All metadata name, value pairs. - */ - protected abstract void onChange(Map metadataValues) throws CacheException; - private void apply(ArrayList removedValues, Map editedValues) throws CacheException { synchronized (metadata) { @@ -101,7 +119,9 @@ public abstract class AbstractContentMetadata implements ContentMetadata { metadata.remove(removedValues.get(i)); } metadata.putAll(editedValues); - onChange(Collections.unmodifiableMap(metadata)); + if (changeListener != null) { + changeListener.onChange(this, Collections.unmodifiableMap(metadata)); + } } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadataTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadataTest.java similarity index 87% rename from library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadataTest.java rename to library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadataTest.java index 5dc99bc654..780cc8182d 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadataTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/DefaultContentMetadataTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; import com.google.android.exoplayer2.upstream.cache.ContentMetadata.Editor; +import com.google.android.exoplayer2.upstream.cache.DefaultContentMetadata.ChangeListener; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -30,14 +31,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -/** Tests {@link AbstractContentMetadata}. */ +/** Tests {@link DefaultContentMetadata}. */ @RunWith(RobolectricTestRunner.class) -public class AbstractContentMetadataTest { +public class DefaultContentMetadataTest { - private FakeAbstractContentMetadata contentMetadata; + private DefaultContentMetadata contentMetadata; + private FakeChangeListener changeListener; @Before public void setUp() throws Exception { + changeListener = new FakeChangeListener(); contentMetadata = createAbstractContentMetadata(); } @@ -156,32 +159,31 @@ public class AbstractContentMetadataTest { editor.set("metadata name", "edited value"); editor.remove("metadata name2"); editor.commit(); - assertThat(contentMetadata.remainingValues).containsExactly("metadata name", "metadata name3"); + assertThat(changeListener.remainingValues).containsExactly("metadata name", "metadata name3"); } - private FakeAbstractContentMetadata createAbstractContentMetadata(String... pairs) { + private DefaultContentMetadata createAbstractContentMetadata(String... pairs) { assertThat(pairs.length % 2).isEqualTo(0); HashMap map = new HashMap<>(); for (int i = 0; i < pairs.length; i += 2) { map.put(pairs[i], getBytes(pairs[i + 1])); } - return new FakeAbstractContentMetadata(Collections.unmodifiableMap(map)); + DefaultContentMetadata metadata = new DefaultContentMetadata(Collections.unmodifiableMap(map)); + metadata.setChangeListener(changeListener); + return metadata; } private static byte[] getBytes(String value) { return value.getBytes(Charset.forName(C.UTF8_NAME)); } - private static class FakeAbstractContentMetadata extends AbstractContentMetadata { + private static class FakeChangeListener implements ChangeListener { private ArrayList remainingValues; - private FakeAbstractContentMetadata(Map metadataValues) { - super(metadataValues); - } - @Override - protected void onChange(Map metadataValues) throws CacheException { + public void onChange(DefaultContentMetadata contentMetadata, Map metadataValues) + throws CacheException { remainingValues = new ArrayList<>(metadataValues.keySet()); } }