Rename Shadow*Looper classes (PR#4868)

ShadowLooper -> ShadowLegacyLooper
ShadowRealisticLooper -> ShadowPausedLooper
ShadowBaseLooper -> ShadowLooper

And all public methods from ShadowLegacyLooper get pushed up to ShadowLooper

Pull Request: https://github.com/robolectric/robolectric/pull/4868

Copybara: OK

Also adjust Google3 tests  using custom looper shadows where necessary.
Convert exoplayer to paused looper to eliminate reliance on custom shadows

PiperOrigin-RevId: 243839311
This commit is contained in:
olly 2019-04-16 18:56:09 +01:00 committed by Andrew Lewis
parent 10f3b8db6e
commit af5131e393
18 changed files with 38 additions and 278 deletions

View File

@ -20,8 +20,9 @@ project.ext {
compileSdkVersion = 28
dexmakerVersion = '2.21.0'
mockitoVersion = '2.25.0'
robolectricVersion = '4.2'
robolectricVersion = '4.3-alpha-2'
autoValueVersion = '1.6'
autoServiceVersion = '1.0-rc4'
checkerframeworkVersion = '2.5.0'
androidXTestVersion = '1.1.0'
modulePrefix = ':'

View File

@ -50,7 +50,6 @@ import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.FakeTrackSelection;
import com.google.android.exoplayer2.testutil.FakeTrackSelector;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.Allocator;
@ -68,11 +67,11 @@ import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit test for {@link ExoPlayer}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public final class ExoPlayerTest {
/**

View File

@ -48,7 +48,6 @@ import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner.Builder;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeRenderer;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
@ -58,11 +57,12 @@ import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
/** Integration test for {@link AnalyticsCollector}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(Mode.PAUSED)
public final class AnalyticsCollectorTest {
private static final int EVENT_PLAYER_STATE_CHANGED = 0;

View File

@ -24,7 +24,6 @@ import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import java.util.HashMap;
import org.junit.After;
import org.junit.Before;
@ -32,11 +31,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Tests {@link OfflineLicenseHelper}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class OfflineLicenseHelperTest {
private OfflineLicenseHelper<?> offlineLicenseHelper;

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.offline;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowBaseLooper.shadowMainLooper;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -34,7 +35,6 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeRenderer;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
@ -51,12 +51,11 @@ import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link DownloadHelper}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class DownloadHelperTest {
private static final String TEST_DOWNLOAD_TYPE = "downloadType";
@ -426,7 +425,7 @@ public class DownloadHelperTest {
}
});
while (!preparedCondition.block(0)) {
ShadowLooper.runMainLooperToNextTask();
shadowMainLooper().idleFor(shadowMainLooper().getNextScheduledTaskTime());
}
if (prepareException.get() != null) {
throw prepareException.get();

View File

@ -24,7 +24,6 @@ import com.google.android.exoplayer2.offline.Download.State;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
@ -41,12 +40,13 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadows.ShadowLog;
/** Tests {@link DownloadManager}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(Mode.PAUSED)
public class DownloadManagerTest {
/** Used to check if condition becomes true in this time interval. */

View File

@ -35,7 +35,6 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
@ -43,11 +42,12 @@ import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
/** Unit tests for {@link ClippingMediaSource}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(Mode.PAUSED)
public final class ClippingMediaSourceTest {
private static final long TEST_PERIOD_DURATION_US = 1000000;

View File

@ -34,7 +34,6 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException;
import java.util.ArrayList;
@ -44,11 +43,11 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link ConcatenatingMediaSource}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public final class ConcatenatingMediaSourceTest {
private ConcatenatingMediaSource mediaSource;

View File

@ -23,17 +23,16 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link LoopingMediaSource}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class LoopingMediaSourceTest {
private FakeTimeline multiWindowTimeline;

View File

@ -26,15 +26,14 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link MergingMediaSource}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class MergingMediaSourceTest {
@Test

View File

@ -35,7 +35,6 @@ import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegm
import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
@ -45,11 +44,11 @@ import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link DashMediaPeriod}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public final class DashMediaPeriodTest {
@Test

View File

@ -36,7 +36,6 @@ import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource.Factory;
@ -52,12 +51,12 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowLog;
/** Tests {@link DownloadManager}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class DownloadManagerDashTest {
private static final int ASSERT_TRUE_TIMEOUT = 1000;

View File

@ -40,7 +40,6 @@ import com.google.android.exoplayer2.scheduler.Scheduler;
import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource;
@ -58,11 +57,11 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link DownloadService}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class DownloadServiceDashTest {
private SimpleCache cache;

View File

@ -32,7 +32,6 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist;
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
@ -43,11 +42,11 @@ import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit test for {@link HlsMediaPeriod}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public final class HlsMediaPeriodTest {
@Test

View File

@ -28,7 +28,6 @@ import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispat
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts;
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
@ -36,11 +35,11 @@ import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.MimeTypes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link SsMediaPeriod}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public class SsMediaPeriodTest {
@Test

View File

@ -26,11 +26,11 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
/** Unit test for {@link FakeClock}. */
@RunWith(AndroidJUnit4.class)
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
@LooperMode(LooperMode.Mode.PAUSED)
public final class FakeClockTest {
private static final long TIMEOUT_MS = 10000;

View File

@ -42,4 +42,5 @@ dependencies {
api project(modulePrefix + 'testutils')
implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:1.0.1'
annotationProcessor 'com.google.auto.service:auto-service:' + autoServiceVersion
}

View File

@ -1,231 +0,0 @@
/*
* Copyright (C) 2018 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.testutil;
import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.util.ReflectionHelpers.callInstanceMethod;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Util;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowMessageQueue;
/** Collection of shadow classes used to run tests with Robolectric which require Loopers. */
public final class RobolectricUtil {
private static final AtomicLong sequenceNumberGenerator = new AtomicLong(0);
private static final int ANY_MESSAGE = Integer.MIN_VALUE;
private RobolectricUtil() {}
/**
* A custom implementation of Robolectric's ShadowLooper which runs all scheduled messages in the
* loop method of the looper. Also ensures to correctly emulate the message order of the real
* message loop and to avoid blocking caused by Robolectric's default implementation.
*
* <p>Only works in conjunction with {@link CustomMessageQueue}. Note that the test's {@code
* SystemClock} is not advanced automatically.
*/
@Implements(Looper.class)
public static final class CustomLooper extends ShadowLooper {
private final PriorityBlockingQueue<PendingMessage> pendingMessages;
private final CopyOnWriteArraySet<RemovedMessage> removedMessages;
public CustomLooper() {
pendingMessages = new PriorityBlockingQueue<>();
removedMessages = new CopyOnWriteArraySet<>();
}
@Implementation
public static void loop() {
Looper looper = Looper.myLooper();
if (shadowOf(looper) instanceof CustomLooper) {
((CustomLooper) shadowOf(looper)).doLoop();
}
}
@Implementation
@Override
public void quitUnchecked() {
super.quitUnchecked();
// Insert message at the front of the queue to quit loop as soon as possible.
addPendingMessage(/* message= */ null, /* when= */ Long.MIN_VALUE);
}
private void addPendingMessage(@Nullable Message message, long when) {
pendingMessages.put(new PendingMessage(message, when));
}
private void removeMessages(Handler handler, int what, Object object) {
RemovedMessage newRemovedMessage = new RemovedMessage(handler, what, object);
removedMessages.add(newRemovedMessage);
for (RemovedMessage removedMessage : removedMessages) {
if (removedMessage != newRemovedMessage
&& removedMessage.handler == handler
&& removedMessage.what == what
&& removedMessage.object == object) {
removedMessages.remove(removedMessage);
}
}
}
private void doLoop() {
boolean wasInterrupted = false;
while (true) {
try {
PendingMessage pendingMessage = pendingMessages.take();
if (pendingMessage.message == null) {
// Null message is signal to end message loop.
return;
}
// Call through to real {@code Message.markInUse()} and {@code Message.recycle()} to
// ensure message recycling works. This is also done in Robolectric's own implementation
// of the message queue.
callInstanceMethod(pendingMessage.message, "markInUse");
Handler target = pendingMessage.message.getTarget();
if (target != null) {
boolean isRemoved = false;
for (RemovedMessage removedMessage : removedMessages) {
if (removedMessage.handler == target
&& (removedMessage.what == ANY_MESSAGE
|| removedMessage.what == pendingMessage.message.what)
&& (removedMessage.object == null
|| removedMessage.object == pendingMessage.message.obj)
&& pendingMessage.sequenceNumber < removedMessage.sequenceNumber) {
isRemoved = true;
}
}
if (!isRemoved) {
try {
if (wasInterrupted) {
wasInterrupted = false;
// Restore the interrupt status flag, so long-running messages will exit early.
Thread.currentThread().interrupt();
}
target.dispatchMessage(pendingMessage.message);
} catch (Throwable t) {
// Interrupt the main thread to terminate the test. Robolectric's HandlerThread will
// print the rethrown error to standard output.
Looper.getMainLooper().getThread().interrupt();
throw t;
}
}
}
if (Util.SDK_INT >= 21) {
callInstanceMethod(pendingMessage.message, "recycleUnchecked");
} else {
callInstanceMethod(pendingMessage.message, "recycle");
}
} catch (InterruptedException e) {
wasInterrupted = true;
}
}
}
}
/**
* Custom implementation of Robolectric's ShadowMessageQueue which is needed to let {@link
* CustomLooper} work as intended.
*/
@Implements(MessageQueue.class)
public static final class CustomMessageQueue extends ShadowMessageQueue {
private final Thread looperThread;
public CustomMessageQueue() {
looperThread = Thread.currentThread();
}
@Implementation
@Override
public boolean enqueueMessage(Message msg, long when) {
Looper looper = ShadowLooper.getLooperForThread(looperThread);
if (shadowOf(looper) instanceof CustomLooper
&& shadowOf(looper) != shadowOf(Looper.getMainLooper())) {
((CustomLooper) shadowOf(looper)).addPendingMessage(msg, when);
} else {
super.enqueueMessage(msg, when);
}
return true;
}
@Implementation
public void removeMessages(Handler handler, int what, Object object) {
Looper looper = ShadowLooper.getLooperForThread(looperThread);
if (shadowOf(looper) instanceof CustomLooper
&& shadowOf(looper) != shadowOf(Looper.getMainLooper())) {
((CustomLooper) shadowOf(looper)).removeMessages(handler, what, object);
}
}
@Implementation
public void removeCallbacksAndMessages(Handler handler, Object object) {
Looper looper = ShadowLooper.getLooperForThread(looperThread);
if (shadowOf(looper) instanceof CustomLooper
&& shadowOf(looper) != shadowOf(Looper.getMainLooper())) {
((CustomLooper) shadowOf(looper)).removeMessages(handler, ANY_MESSAGE, object);
}
}
}
private static final class PendingMessage implements Comparable<PendingMessage> {
public final @Nullable Message message;
public final long when;
public final long sequenceNumber;
public PendingMessage(@Nullable Message message, long when) {
this.message = message;
this.when = when;
sequenceNumber = sequenceNumberGenerator.getAndIncrement();
}
@Override
public int compareTo(@NonNull PendingMessage other) {
int res = Util.compareLong(this.when, other.when);
if (res == 0 && this != other) {
res = Util.compareLong(this.sequenceNumber, other.sequenceNumber);
}
return res;
}
}
private static final class RemovedMessage {
public final Handler handler;
public final int what;
public final Object object;
public final long sequenceNumber;
public RemovedMessage(Handler handler, int what, Object object) {
this.handler = handler;
this.what = what;
this.object = object;
this.sequenceNumber = sequenceNumberGenerator.get();
}
}
}