Implement Bundleable for Timeline
PiperOrigin-RevId: 362474276
This commit is contained in:
parent
3f4f2f90b5
commit
f8fb9dd606
@ -32,6 +32,7 @@ project.ext {
|
||||
androidxAnnotationVersion = '1.1.0'
|
||||
androidxAppCompatVersion = '1.1.0'
|
||||
androidxCollectionVersion = '1.1.0'
|
||||
androidxCoreVersion = '1.3.2'
|
||||
androidxFuturesVersion = '1.1.0'
|
||||
androidxMediaVersion = '1.2.1'
|
||||
androidxMedia2Version = '1.1.2'
|
||||
@ -42,6 +43,7 @@ project.ext {
|
||||
androidxTestRunnerVersion = '1.3.0'
|
||||
androidxTestRulesVersion = '1.3.0'
|
||||
androidxTestServicesStorageVersion = '1.3.0'
|
||||
androidxTestTruthVersion = '1.3.0'
|
||||
truthVersion = '1.0'
|
||||
modulePrefix = ':'
|
||||
if (gradle.ext.has('exoplayerModulePrefix')) {
|
||||
|
@ -26,6 +26,7 @@ dependencies {
|
||||
exclude group: 'org.codehaus.mojo', module: 'animal-sniffer-annotations'
|
||||
}
|
||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||
implementation 'androidx.core:core:' + androidxCoreVersion
|
||||
compileOnly 'com.google.code.findbugs:jsr305:' + jsr305Version
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion
|
||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link Binder} to transfer a list of {@link Bundle Bundles} across processes by splitting the
|
||||
* list into multiple transactions.
|
||||
*
|
||||
* <p>Note: Using this class causes synchronous binder calls in the opposite direction regardless of
|
||||
* the "oneway" property.
|
||||
*
|
||||
* <p>Example usage:
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Sender
|
||||
* List<Bundle> list = ...;
|
||||
* IBinder binder = new BundleListRetriever(list);
|
||||
* Bundle bundle = new Bundle();
|
||||
* bundle.putBinder("list", binder);
|
||||
*
|
||||
* // Receiver
|
||||
* Bundle bundle = ...; // Received from the sender
|
||||
* IBinder binder = bundle.getBinder("list");
|
||||
* List<Bundle> list = BundleListRetriever.getList(binder);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class BundleListRetriever extends Binder {
|
||||
|
||||
// Soft limit of an IPC buffer size
|
||||
private static final int SUGGESTED_MAX_IPC_SIZE =
|
||||
Util.SDK_INT >= 30 ? IBinder.getSuggestedMaxIpcSizeBytes() : 64 * 1024;
|
||||
|
||||
private static final int REPLY_END_OF_LIST = 0;
|
||||
private static final int REPLY_CONTINUE = 1;
|
||||
private static final int REPLY_BREAK = 2;
|
||||
|
||||
private final ImmutableList<Bundle> list;
|
||||
|
||||
/** Creates a {@link Binder} to send a list of {@link Bundle Bundles} to another process. */
|
||||
public BundleListRetriever(List<Bundle> list) {
|
||||
this.list = ImmutableList.copyOf(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onTransact(int code, Parcel data, @Nullable Parcel reply, int flags)
|
||||
throws RemoteException {
|
||||
if (code != FIRST_CALL_TRANSACTION) {
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
}
|
||||
|
||||
if (reply == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = list.size();
|
||||
int index = data.readInt();
|
||||
while (index < count && reply.dataSize() < SUGGESTED_MAX_IPC_SIZE) {
|
||||
reply.writeInt(REPLY_CONTINUE);
|
||||
reply.writeBundle(list.get(index));
|
||||
index++;
|
||||
}
|
||||
reply.writeInt(index < count ? REPLY_BREAK : REPLY_END_OF_LIST);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of {@link Bundle Bundles} from a {@link BundleListRetriever}.
|
||||
*
|
||||
* @param binder A binder interface backed by {@link BundleListRetriever}.
|
||||
* @return The list of {@link Bundle Bundles}.
|
||||
*/
|
||||
public static ImmutableList<Bundle> getList(IBinder binder) {
|
||||
ImmutableList.Builder<Bundle> builder = ImmutableList.builder();
|
||||
|
||||
int index = 0;
|
||||
int replyCode = REPLY_CONTINUE;
|
||||
|
||||
while (replyCode != REPLY_END_OF_LIST) {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
try {
|
||||
data.writeInt(index);
|
||||
try {
|
||||
binder.transact(FIRST_CALL_TRANSACTION, data, reply, /* flags= */ 0);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
while ((replyCode = reply.readInt()) == REPLY_CONTINUE) {
|
||||
builder.add(checkNotNull(reply.readBundle()));
|
||||
index++;
|
||||
}
|
||||
} finally {
|
||||
reply.recycle();
|
||||
data.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
@ -19,16 +19,21 @@ import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.BundleCompat;
|
||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A flexible representation of the structure of media. A timeline is able to represent the
|
||||
@ -124,7 +129,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
* <p>This case includes mid-roll ad groups, which are defined as part of the timeline's single
|
||||
* period. The period can be queried for information about the ad groups and the ads they contain.
|
||||
*/
|
||||
public abstract class Timeline {
|
||||
public abstract class Timeline implements Bundleable {
|
||||
|
||||
/**
|
||||
* Holds information about a window in a {@link Timeline}. A window usually corresponds to one
|
||||
@ -1245,4 +1250,148 @@ public abstract class Timeline {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bundleable implementation.
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({FIELD_WINDOWS, FIELD_PERIODS})
|
||||
private @interface FieldNumber {}
|
||||
|
||||
private static final int FIELD_WINDOWS = 0;
|
||||
private static final int FIELD_PERIODS = 1;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The {@link #getWindow(int, Window)} windows} and {@link #getPeriod(int, Period) periods} of
|
||||
* an instance restored by {@link #CREATOR} may have missing fields as described in {@link
|
||||
* Window#toBundle()} and {@link Period#toBundle()}.
|
||||
*/
|
||||
@Override
|
||||
public final Bundle toBundle() {
|
||||
List<Bundle> windowBundles = new ArrayList<>();
|
||||
int windowCount = getWindowCount();
|
||||
for (int i = 0; i < windowCount; i++) {
|
||||
Window window = new Window();
|
||||
getWindow(i, window, /* defaultPositionProjectionUs= */ 0);
|
||||
windowBundles.add(window.toBundle());
|
||||
}
|
||||
|
||||
List<Bundle> periodBundles = new ArrayList<>();
|
||||
int periodCount = getPeriodCount();
|
||||
for (int i = 0; i < periodCount; i++) {
|
||||
Period period = new Period();
|
||||
getPeriod(i, period, /* setIds= */ false);
|
||||
periodBundles.add(period.toBundle());
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
BundleCompat.putBinder(
|
||||
bundle, keyForField(FIELD_WINDOWS), new BundleListRetriever(windowBundles));
|
||||
BundleCompat.putBinder(
|
||||
bundle, keyForField(FIELD_PERIODS), new BundleListRetriever(periodBundles));
|
||||
return bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object that can restore a {@link Timeline} from a {@link Bundle}.
|
||||
*
|
||||
* <p>The {@link #getWindow(int, Window)} windows} and {@link #getPeriod(int, Period) periods} of
|
||||
* a restored instance may have missing fields as described in {@link Window#CREATOR} and {@link
|
||||
* Period#CREATOR}.
|
||||
*/
|
||||
public static final Creator<Timeline> CREATOR = Timeline::fromBundle;
|
||||
|
||||
private static Timeline fromBundle(Bundle bundle) {
|
||||
ImmutableList<Window> windows =
|
||||
fromBundleListRetriever(
|
||||
Window.CREATOR, BundleCompat.getBinder(bundle, keyForField(FIELD_WINDOWS)));
|
||||
ImmutableList<Period> periods =
|
||||
fromBundleListRetriever(
|
||||
Period.CREATOR, BundleCompat.getBinder(bundle, keyForField(FIELD_PERIODS)));
|
||||
return new RemotableTimeline(windows, periods);
|
||||
}
|
||||
|
||||
private static <T extends Bundleable> ImmutableList<T> fromBundleListRetriever(
|
||||
Creator<T> creator, @Nullable IBinder binder) {
|
||||
if (binder == null) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
ImmutableList.Builder<T> builder = new ImmutableList.Builder<>();
|
||||
List<Bundle> bundleList = BundleListRetriever.getList(binder);
|
||||
for (int i = 0; i < bundleList.size(); i++) {
|
||||
builder.add(creator.fromBundle(bundleList.get(i)));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static String keyForField(@FieldNumber int field) {
|
||||
return Integer.toString(field, Character.MAX_RADIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete class of {@link Timeline} to restore a {@link Timeline} instance from a {@link
|
||||
* Bundle} sent by another process via {@link IBinder}.
|
||||
*/
|
||||
private static final class RemotableTimeline extends Timeline {
|
||||
|
||||
private final ImmutableList<Window> windows;
|
||||
private final ImmutableList<Period> periods;
|
||||
|
||||
public RemotableTimeline(ImmutableList<Window> windows, ImmutableList<Period> periods) {
|
||||
this.windows = windows;
|
||||
this.periods = periods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWindowCount() {
|
||||
return windows.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindow(
|
||||
int windowIndex, Window window, long ignoredDefaultPositionProjectionUs) {
|
||||
Window w = windows.get(windowIndex);
|
||||
window.set(
|
||||
w.uid,
|
||||
w.mediaItem,
|
||||
w.manifest,
|
||||
w.presentationStartTimeMs,
|
||||
w.windowStartTimeMs,
|
||||
w.elapsedRealtimeEpochOffsetMs,
|
||||
w.isSeekable,
|
||||
w.isDynamic,
|
||||
w.liveConfiguration,
|
||||
w.defaultPositionUs,
|
||||
w.durationUs,
|
||||
w.firstPeriodIndex,
|
||||
w.lastPeriodIndex,
|
||||
w.positionInFirstPeriodUs);
|
||||
window.isPlaceholder = w.isPlaceholder;
|
||||
return window;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPeriodCount() {
|
||||
return periods.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean ignoredSetIds) {
|
||||
Period p = periods.get(periodIndex);
|
||||
return period.set(
|
||||
p.id, p.uid, p.windowIndex, p.durationUs, p.positionInWindowUs, p.adPlaybackState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfPeriod(Object uid) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUidOfPeriod(int periodIndex) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.ext.truth.os.BundleSubject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for {@link BundleListRetriever}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BundleListRetrieverTest {
|
||||
|
||||
@Test
|
||||
public void getList_preservedLargeList() {
|
||||
int count = 100_000;
|
||||
List<Bundle> listBefore = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("i", i);
|
||||
listBefore.add(bundle);
|
||||
}
|
||||
|
||||
List<Bundle> listAfter = BundleListRetriever.getList(new BundleListRetriever(listBefore));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Bundle bundle = listAfter.get(i);
|
||||
BundleSubject.assertThat(bundle).integer("i").isEqualTo(i);
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.MediaItem.LiveConfiguration;
|
||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
||||
import com.google.android.exoplayer2.testutil.TimelineAsserts;
|
||||
@ -201,6 +202,41 @@ public class TimelineTest {
|
||||
assertThat(period.hashCode()).isEqualTo(otherPeriod.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundtripViaBundle_ofTimeline_yieldsEqualInstanceExceptIdsAndManifest() {
|
||||
Timeline timeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 2,
|
||||
/* id= */ new Object(),
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* isLive= */ true,
|
||||
/* isPlaceholder= */ false,
|
||||
/* durationUs= */ 2,
|
||||
/* defaultPositionUs= */ 22,
|
||||
/* windowOffsetInFirstPeriodUs= */ 222,
|
||||
AdPlaybackState.NONE,
|
||||
new MediaItem.Builder().setMediaId("mediaId2").build()),
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 3,
|
||||
/* id= */ new Object(),
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* isLive= */ true,
|
||||
/* isPlaceholder= */ false,
|
||||
/* durationUs= */ 3,
|
||||
/* defaultPositionUs= */ 33,
|
||||
/* windowOffsetInFirstPeriodUs= */ 333,
|
||||
AdPlaybackState.NONE,
|
||||
new MediaItem.Builder().setMediaId("mediaId3").build()));
|
||||
|
||||
Timeline restoredTimeline = Timeline.CREATOR.fromBundle(timeline.toBundle());
|
||||
|
||||
TimelineAsserts.assertEqualsExceptIdsAndManifest(
|
||||
/* expectedTimeline= */ timeline, /* actualTimeline= */ restoredTimeline);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundtripViaBundle_ofWindow_yieldsEqualInstanceExceptUidAndManifest() {
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
@ -229,9 +265,8 @@ public class TimelineTest {
|
||||
Timeline.Window restoredWindow = Timeline.Window.CREATOR.fromBundle(window.toBundle());
|
||||
|
||||
assertThat(restoredWindow.manifest).isNull();
|
||||
window.uid = restoredWindow.uid;
|
||||
window.manifest = null;
|
||||
assertThat(restoredWindow).isEqualTo(window);
|
||||
TimelineAsserts.assertWindowEqualsExceptUidAndManifest(
|
||||
/* expectedWindow= */ window, /* actualWindow= */ restoredWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -245,9 +280,10 @@ public class TimelineTest {
|
||||
|
||||
Timeline.Period restoredPeriod = Timeline.Period.CREATOR.fromBundle(period.toBundle());
|
||||
|
||||
period.id = null;
|
||||
period.uid = null;
|
||||
assertThat(restoredPeriod).isEqualTo(period);
|
||||
assertThat(restoredPeriod.id).isNull();
|
||||
assertThat(restoredPeriod.uid).isNull();
|
||||
TimelineAsserts.assertPeriodEqualsExceptIds(
|
||||
/* expectedPeriod= */ period, /* actualPeriod= */ restoredPeriod);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Populates the deprecated window.tag property.
|
||||
|
@ -17,6 +17,7 @@ dependencies {
|
||||
api 'org.mockito:mockito-core:' + mockitoVersion
|
||||
api 'androidx.test:core:' + androidxTestCoreVersion
|
||||
api 'androidx.test.ext:junit:' + androidxTestJUnitVersion
|
||||
api 'androidx.test.ext:truth:' + androidxTestTruthVersion
|
||||
api 'junit:junit:' + junitVersion
|
||||
api 'com.google.truth:truth:' + truthVersion
|
||||
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
@ -27,15 +28,13 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
|
||||
/** Unit test for {@link Timeline}. */
|
||||
/** Assertion methods for {@link Timeline}. */
|
||||
public final class TimelineAsserts {
|
||||
|
||||
private static final int[] REPEAT_MODES = {
|
||||
Player.REPEAT_MODE_OFF, Player.REPEAT_MODE_ONE, Player.REPEAT_MODE_ALL
|
||||
};
|
||||
|
||||
private TimelineAsserts() {}
|
||||
|
||||
/** Assert that timeline is empty (i.e. has no windows or periods). */
|
||||
public static void assertEmpty(Timeline timeline) {
|
||||
assertWindowTags(timeline);
|
||||
@ -173,4 +172,64 @@ public final class TimelineAsserts {
|
||||
assertThat(period.getAdGroupCount()).isEqualTo(expectedAdGroupCounts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@link Timeline timelines} are equal except {@link Window#uid}, {@link
|
||||
* Window#manifest}, {@link Period#id}, and {@link Period#uid}.
|
||||
*/
|
||||
public static void assertEqualsExceptIdsAndManifest(
|
||||
Timeline expectedTimeline, Timeline actualTimeline) {
|
||||
assertThat(actualTimeline.getWindowCount()).isEqualTo(expectedTimeline.getWindowCount());
|
||||
for (int i = 0; i < actualTimeline.getWindowCount(); i++) {
|
||||
Window expectedWindow = new Window();
|
||||
Window actualWindow = new Window();
|
||||
assertWindowEqualsExceptUidAndManifest(
|
||||
expectedTimeline.getWindow(i, expectedWindow, /* defaultPositionProjectionUs= */ 0),
|
||||
actualTimeline.getWindow(i, actualWindow, /* defaultPositionProjectionUs= */ 0));
|
||||
}
|
||||
assertThat(actualTimeline.getPeriodCount()).isEqualTo(expectedTimeline.getPeriodCount());
|
||||
for (int i = 0; i < actualTimeline.getPeriodCount(); i++) {
|
||||
Period expectedPeriod = new Period();
|
||||
Period actualPeriod = new Period();
|
||||
assertPeriodEqualsExceptIds(
|
||||
expectedTimeline.getPeriod(i, expectedPeriod, /* setIds= */ false),
|
||||
actualTimeline.getPeriod(i, actualPeriod, /* setIds= */ false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@link Window windows} are equal except {@link Window#uid} and {@link
|
||||
* Window#manifest}.
|
||||
*/
|
||||
public static void assertWindowEqualsExceptUidAndManifest(
|
||||
Window expectedWindow, Window actualWindow) {
|
||||
Object uid = expectedWindow.uid;
|
||||
@Nullable Object manifest = expectedWindow.manifest;
|
||||
try {
|
||||
expectedWindow.uid = actualWindow.uid;
|
||||
expectedWindow.manifest = actualWindow.manifest;
|
||||
assertThat(actualWindow).isEqualTo(expectedWindow);
|
||||
} finally {
|
||||
expectedWindow.uid = uid;
|
||||
expectedWindow.manifest = manifest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that {@link Period periods} are equal except {@link Period#id} and {@link Period#uid}.
|
||||
*/
|
||||
public static void assertPeriodEqualsExceptIds(Period expectedPeriod, Period actualPeriod) {
|
||||
@Nullable Object id = expectedPeriod.id;
|
||||
@Nullable Object uid = expectedPeriod.uid;
|
||||
try {
|
||||
expectedPeriod.id = actualPeriod.id;
|
||||
expectedPeriod.uid = actualPeriod.uid;
|
||||
assertThat(actualPeriod).isEqualTo(expectedPeriod);
|
||||
} finally {
|
||||
expectedPeriod.id = id;
|
||||
expectedPeriod.uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
private TimelineAsserts() {}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user