From d72d25470d3d57da8cb7a07aac886d5772522932 Mon Sep 17 00:00:00 2001 From: gyumin Date: Thu, 4 Feb 2021 14:03:21 +0000 Subject: [PATCH] Add Bundleable interface It's for classes to clearly denote they support bundling and it gives us a good place to document the best practice to implement fromBundle. PiperOrigin-RevId: 355609942 --- .../google/android/exoplayer2/Bundleable.java | 52 +++++++++++++++++++ .../exoplayer2/audio/AudioAttributes.java | 39 +++++++------- .../android/exoplayer2/device/DeviceInfo.java | 20 +++---- .../exoplayer2/audio/AudioAttributesTest.java | 3 +- .../exoplayer2/device/DeviceInfoTest.java | 2 +- 5 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 library/common/src/main/java/com/google/android/exoplayer2/Bundleable.java diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Bundleable.java b/library/common/src/main/java/com/google/android/exoplayer2/Bundleable.java new file mode 100644 index 0000000000..82b40a95d1 --- /dev/null +++ b/library/common/src/main/java/com/google/android/exoplayer2/Bundleable.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 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. + */ +package com.google.android.exoplayer2; + +import android.os.Bundle; + +/** + * Interface for classes whose instance can be stored in a {@link Bundle} by {@link #toBundle()} and + * can be restored from the {@link Bundle} by using the static {@code CREATOR} field that implements + * {@link Bundleable.Creator}. + * + *

For example, a {@link Bundleable} class {@code Foo} supports the following: + * + *

{@code
+ * Foo foo = ...;
+ * Bundle fooBundle = foo.toBundle();
+ * Foo restoredFoo = Foo.CREATOR.fromBundle(fooBundle);
+ * assertThat(restoredFoo).isEqualTo(foo);
+ * }
+ */ +public interface Bundleable { + + /** Returns a {@link Bundle} representing the information stored in this object. */ + Bundle toBundle(); + + /** Interface for the static {@code CREATOR} field of {@link Bundleable} classes. */ + interface Creator { + + /** + * Restores a {@link Bundleable} instance from a {@link Bundle} produced by {@link + * Bundleable#toBundle()}. + * + *

It guarantees the compatibility of {@link Bundle} representations produced by different + * versions of {@link Bundleable#toBundle()} by providing best default values for missing + * fields. It may throw an {@link IllegalArgumentException} if any essential fields are missing. + */ + T fromBundle(Bundle bundle); + } +} diff --git a/library/common/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java b/library/common/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java index 35800e6bbd..f62c6b424a 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio; import android.os.Bundle; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import com.google.android.exoplayer2.Bundleable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Util; @@ -32,7 +33,7 @@ import com.google.android.exoplayer2.util.Util; *

This class is based on {@link android.media.AudioAttributes}, but can be used on all supported * API versions. */ -public final class AudioAttributes { +public final class AudioAttributes implements Bundleable { private static final String FIELD_CONTENT_TYPE = "contentType"; private static final String FIELD_FLAGS = "flags"; @@ -165,7 +166,7 @@ public final class AudioAttributes { return result; } - /** Converts this instance into a {@link Bundle}. */ + @Override public Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putInt(FIELD_CONTENT_TYPE, contentType); @@ -175,21 +176,21 @@ public final class AudioAttributes { return bundle; } - /** Creates an {@link AudioAttributes} instance from a {@link Bundle}. */ - public static AudioAttributes fromBundle(Bundle bundle) { - Builder builder = new Builder(); - if (bundle.containsKey(FIELD_CONTENT_TYPE)) { - builder.setContentType(bundle.getInt(FIELD_CONTENT_TYPE)); - } - if (bundle.containsKey(FIELD_FLAGS)) { - builder.setFlags(bundle.getInt(FIELD_FLAGS)); - } - if (bundle.containsKey(FIELD_USAGE)) { - builder.setUsage(bundle.getInt(FIELD_USAGE)); - } - if (bundle.containsKey(FIELD_ALLOWED_CAPTURE_POLICY)) { - builder.setAllowedCapturePolicy(bundle.getInt(FIELD_ALLOWED_CAPTURE_POLICY)); - } - return builder.build(); - } + public static final Creator CREATOR = + bundle -> { + Builder builder = new Builder(); + if (bundle.containsKey(FIELD_CONTENT_TYPE)) { + builder.setContentType(bundle.getInt(FIELD_CONTENT_TYPE)); + } + if (bundle.containsKey(FIELD_FLAGS)) { + builder.setFlags(bundle.getInt(FIELD_FLAGS)); + } + if (bundle.containsKey(FIELD_USAGE)) { + builder.setUsage(bundle.getInt(FIELD_USAGE)); + } + if (bundle.containsKey(FIELD_ALLOWED_CAPTURE_POLICY)) { + builder.setAllowedCapturePolicy(bundle.getInt(FIELD_ALLOWED_CAPTURE_POLICY)); + } + return builder.build(); + }; } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java index b640d7a820..6e01704884 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/device/DeviceInfo.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.device; import android.os.Bundle; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.Bundleable; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -25,7 +26,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** Information about the playback device. */ -public final class DeviceInfo { +public final class DeviceInfo implements Bundleable { private static final String FIELD_PLAYBACK_TYPE = "playbackType"; private static final String FIELD_MIN_VOLUME = "minVolume"; @@ -86,7 +87,7 @@ public final class DeviceInfo { return result; } - /** Converts this instance into a {@link Bundle}. */ + @Override public Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putInt(FIELD_PLAYBACK_TYPE, playbackType); @@ -95,11 +96,12 @@ public final class DeviceInfo { return bundle; } - /** Creates an {@link DeviceInfo} instance from a {@link Bundle}. */ - public static DeviceInfo fromBundle(Bundle bundle) { - int playbackType = bundle.getInt(FIELD_PLAYBACK_TYPE, /* defaultValue= */ PLAYBACK_TYPE_LOCAL); - int minVolume = bundle.getInt(FIELD_MIN_VOLUME, /* defaultValue= */ 0); - int maxVolume = bundle.getInt(FIELD_MAX_VOLUME, /* defaultValue= */ 0); - return new DeviceInfo(playbackType, minVolume, maxVolume); - } + public static final Creator CREATOR = + bundle -> { + int playbackType = + bundle.getInt(FIELD_PLAYBACK_TYPE, /* defaultValue= */ PLAYBACK_TYPE_LOCAL); + int minVolume = bundle.getInt(FIELD_MIN_VOLUME, /* defaultValue= */ 0); + int maxVolume = bundle.getInt(FIELD_MAX_VOLUME, /* defaultValue= */ 0); + return new DeviceInfo(playbackType, minVolume, maxVolume); + }; } diff --git a/library/common/src/test/java/com/google/android/exoplayer2/audio/AudioAttributesTest.java b/library/common/src/test/java/com/google/android/exoplayer2/audio/AudioAttributesTest.java index 4d8193e662..7435eba047 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/audio/AudioAttributesTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/audio/AudioAttributesTest.java @@ -36,6 +36,7 @@ public class AudioAttributesTest { .setAllowedCapturePolicy(C.ALLOW_CAPTURE_BY_SYSTEM) .build(); - assertThat(AudioAttributes.fromBundle(audioAttributes.toBundle())).isEqualTo(audioAttributes); + assertThat(AudioAttributes.CREATOR.fromBundle(audioAttributes.toBundle())) + .isEqualTo(audioAttributes); } } diff --git a/library/common/src/test/java/com/google/android/exoplayer2/device/DeviceInfoTest.java b/library/common/src/test/java/com/google/android/exoplayer2/device/DeviceInfoTest.java index d8a8e34818..536987b4de 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/device/DeviceInfoTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/device/DeviceInfoTest.java @@ -30,6 +30,6 @@ public class DeviceInfoTest { DeviceInfo deviceInfo = new DeviceInfo(DeviceInfo.PLAYBACK_TYPE_REMOTE, /* minVolume= */ 1, /* maxVolume= */ 9); - assertThat(DeviceInfo.fromBundle(deviceInfo.toBundle())).isEqualTo(deviceInfo); + assertThat(DeviceInfo.CREATOR.fromBundle(deviceInfo.toBundle())).isEqualTo(deviceInfo); } }