AnalyticsCollector implements Player.EventListener,
        MetadataOutput,
        AudioRendererEventListener,
        VideoRendererEventListener,
        MediaSourceEventListener,
        BandwidthMeter.EventListener,
        DefaultDrmSessionEventListener,
        VideoListener,
        AudioListener { public final void notifySeekStarted() { if (!mediaPeriodQueueTracker.isSeeking()) { EventTime eventTime = generatePlayingMediaPeriodEventTime(); mediaPeriodQueueTracker.onSeekStarted(); for (AnalyticsListener listener : listeners) { listener.onSeekStarted(eventTime); } } } AnalyticsCollector(Clock clock); void addListener(AnalyticsListener listener); void removeListener(AnalyticsListener listener); void setPlayer(Player player); final void notifySeekStarted(); final void resetForNewMediaSource(); @Override final void onMetadata(Metadata metadata); @Override final void onAudioEnabled(DecoderCounters counters); @Override final void onAudioDecoderInitialized(
      String decoderName, long initializedTimestampMs, long initializationDurationMs); @Override final void onAudioInputFormatChanged(Format format); @Override final void onAudioSinkUnderrun(
      int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs); @Override final void onAudioDisabled(DecoderCounters counters); @Override final void onAudioSessionId(int audioSessionId); @Override void onAudioAttributesChanged(AudioAttributes audioAttributes); @Override void onVolumeChanged(float audioVolume); @Override final void onVideoEnabled(DecoderCounters counters); @Override final void onVideoDecoderInitialized(
      String decoderName, long initializedTimestampMs, long initializationDurationMs); @Override final void onVideoInputFormatChanged(Format format); @Override final void onDroppedFrames(int count, long elapsedMs); @Override final void onVideoDisabled(DecoderCounters counters); @Override final void onRenderedFirstFrame(@Nullable Surface surface); @Override final void onRenderedFirstFrame(); @Override final void onVideoSizeChanged(
      int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio); @Override void onSurfaceSizeChanged(int width, int height); @Override final void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId); @Override final void onMediaPeriodReleased(int windowIndex, MediaPeriodId mediaPeriodId); @Override final void onLoadStarted(
      int windowIndex,
      @Nullable MediaPeriodId mediaPeriodId,
      LoadEventInfo loadEventInfo,
      MediaLoadData mediaLoadData); @Override final void onLoadCompleted(
      int windowIndex,
      @Nullable MediaPeriodId mediaPeriodId,
      LoadEventInfo loadEventInfo,
      MediaLoadData mediaLoadData); @Override final void onLoadCanceled(
      int windowIndex,
      @Nullable MediaPeriodId mediaPeriodId,
      LoadEventInfo loadEventInfo,
      MediaLoadData mediaLoadData); @Override final void onLoadError(
      int windowIndex,
      @Nullable MediaPeriodId mediaPeriodId,
      LoadEventInfo loadEventInfo,
      MediaLoadData mediaLoadData,
      IOException error,
      boolean wasCanceled); @Override final void onReadingStarted(int windowIndex, MediaPeriodId mediaPeriodId); @Override final void onUpstreamDiscarded(
      int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData); @Override final void onDownstreamFormatChanged(
      int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData); @Override final void onTimelineChanged(Timeline timeline, @Player.TimelineChangeReason int reason); @Override final void onTracksChanged(
      TrackGroupArray trackGroups, TrackSelectionArray trackSelections); @Override final void onLoadingChanged(boolean isLoading); @Override final void onPlayerStateChanged(boolean playWhenReady, @Player.State int playbackState); @Override void onPlaybackSuppressionReasonChanged(
      @PlaybackSuppressionReason int playbackSuppressionReason); @Override void onIsPlayingChanged(boolean isPlaying); @Override final void onRepeatModeChanged(@Player.RepeatMode int repeatMode); @Override final void onShuffleModeEnabledChanged(boolean shuffleModeEnabled); @Override final void onPlayerError(ExoPlaybackException error); @Override final void onPositionDiscontinuity(@Player.DiscontinuityReason int reason); @Override final void onPlaybackParametersChanged(PlaybackParameters playbackParameters); @Override final void onSeekProcessed(); @Override final void onBandwidthSample(int elapsedMs, long bytes, long bitrate); @Override final void onDrmSessionAcquired(); @Override final void onDrmKeysLoaded(); @Override final void onDrmSessionManagerError(Exception error); @Override final void onDrmKeysRestored(); @Override final void onDrmKeysRemoved(); @Override final void onDrmSessionReleased();  }
@Test public void testNotifyExternalEvents() throws Exception { MediaSource mediaSource = new FakeMediaSource(SINGLE_PERIOD_TIMELINE); ActionSchedule actionSchedule = new ActionSchedule.Builder("AnalyticsCollectorTest") .pause() .waitForPlaybackState(Player.STATE_READY) .executeRunnable( new PlayerRunnable() { @Override public void run(SimpleExoPlayer player) { player.getAnalyticsCollector().notifySeekStarted(); } }) .seek( 0) .play() .build(); TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule); populateEventIds(SINGLE_PERIOD_TIMELINE); assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period0); }