public final class

TestDownloadManagerListener

extends java.lang.Object

implements DownloadManager.Listener

 java.lang.Object

↳androidx.media3.test.utils.robolectric.TestDownloadManagerListener

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-test-utils-robolectric', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-test-utils-robolectric
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-test-utils-robolectric:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Allows tests to block for, and assert properties of, calls from a DownloadManager to its .

Summary

Constructors
publicTestDownloadManagerListener(DownloadManager downloadManager)

Methods
public voidassertRemoved(java.lang.String id)

Asserts that the specified download is removed.

public voidassertState(java.lang.String id, int state)

Asserts that the specified download transitions to the specified state.

public voidblockUntilIdle()

Blocks until the manager is idle.

public voidblockUntilIdleAndThrowAnyFailure()

Blocks until the manager is idle and throws if any of the downloads failed.

public voidblockUntilInitialized()

Blocks until the manager is initialized.

public voidonDownloadChanged(DownloadManager downloadManager, Download download, java.lang.Exception finalException)

public voidonDownloadRemoved(DownloadManager downloadManager, Download download)

public voidonIdle(DownloadManager downloadManager)

public voidonInitialized(DownloadManager downloadManager)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public TestDownloadManagerListener(DownloadManager downloadManager)

Methods

public void blockUntilInitialized()

Blocks until the manager is initialized.

public void blockUntilIdle()

Blocks until the manager is idle.

public void blockUntilIdleAndThrowAnyFailure()

Blocks until the manager is idle and throws if any of the downloads failed.

public void assertState(java.lang.String id, int state)

Asserts that the specified download transitions to the specified state.

public void assertRemoved(java.lang.String id)

Asserts that the specified download is removed.

public void onInitialized(DownloadManager downloadManager)

public void onDownloadChanged(DownloadManager downloadManager, Download download, java.lang.Exception finalException)

public void onDownloadRemoved(DownloadManager downloadManager, Download download)

public void onIdle(DownloadManager downloadManager)

Source

/*
 * Copyright (C) 2017 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 androidx.media3.test.utils.robolectric;

import static androidx.media3.test.utils.robolectric.RobolectricUtil.createRobolectricConditionVariable;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.junit.Assert.fail;

import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.offline.Download;
import androidx.media3.exoplayer.offline.DownloadManager;
import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Allows tests to block for, and assert properties of, calls from a {@link DownloadManager} to its
 * {@link DownloadManager.Listener}.
 */
@UnstableApi
public final class TestDownloadManagerListener implements DownloadManager.Listener {

  private static final int TIMEOUT_MS = 10_000;
  private static final int STATE_REMOVED = -1;

  private final DownloadManager downloadManager;
  private final HashMap<String, LinkedBlockingQueue<Integer>> downloadStates;
  private final ConditionVariable initializedCondition;
  private final ConditionVariable idleCondition;

  private @Download.FailureReason int failureReason;

  public TestDownloadManagerListener(DownloadManager downloadManager) {
    this.downloadManager = downloadManager;
    downloadStates = new HashMap<>();
    initializedCondition = createRobolectricConditionVariable();
    idleCondition = createRobolectricConditionVariable();
    downloadManager.addListener(this);
  }

  /** Blocks until the manager is initialized. */
  public void blockUntilInitialized() throws InterruptedException {
    assertThat(initializedCondition.block(TIMEOUT_MS)).isTrue();
  }

  /** Blocks until the manager is idle. */
  public void blockUntilIdle() throws InterruptedException {
    idleCondition.close();
    // If the manager is already idle the condition will be opened by the code immediately below.
    // Else it will be opened by onIdle().
    ConditionVariable checkedOnMainThread = createRobolectricConditionVariable();
    new Handler(downloadManager.getApplicationLooper())
        .post(
            () -> {
              if (downloadManager.isIdle()) {
                idleCondition.open();
              }
              checkedOnMainThread.open();
            });
    assertThat(checkedOnMainThread.block(TIMEOUT_MS)).isTrue();
    assertThat(idleCondition.block(TIMEOUT_MS)).isTrue();
  }

  /** Blocks until the manager is idle and throws if any of the downloads failed. */
  public void blockUntilIdleAndThrowAnyFailure() throws Exception {
    blockUntilIdle();
    if (failureReason != Download.FAILURE_REASON_NONE) {
      throw new Exception("Failure reason: " + failureReason);
    }
  }

  /** Asserts that the specified download transitions to the specified state. */
  public void assertState(String id, @Download.State int state) {
    assertStateInternal(id, state);
  }

  /** Asserts that the specified download is removed. */
  public void assertRemoved(String id) {
    assertStateInternal(id, STATE_REMOVED);
  }

  // DownloadManager.Listener implementation.

  @Override
  public void onInitialized(DownloadManager downloadManager) {
    initializedCondition.open();
  }

  @Override
  public void onDownloadChanged(
      DownloadManager downloadManager, Download download, @Nullable Exception finalException) {
    if (download.state == Download.STATE_FAILED) {
      failureReason = download.failureReason;
    }
    getStateQueue(download.request.id).add(download.state);
  }

  @Override
  public void onDownloadRemoved(DownloadManager downloadManager, Download download) {
    getStateQueue(download.request.id).add(STATE_REMOVED);
  }

  @Override
  public void onIdle(DownloadManager downloadManager) {
    idleCondition.open();
  }

  // Internal logic.

  private void assertStateInternal(String id, int expectedState) {
    while (true) {
      @Nullable Integer state = null;
      try {
        state = getStateQueue(id).poll(TIMEOUT_MS, MILLISECONDS);
      } catch (InterruptedException e) {
        fail("Interrupted: " + e.getMessage());
      }
      if (state != null) {
        if (expectedState == state) {
          return;
        }
      } else {
        fail("Didn't receive expected state: " + expectedState);
      }
    }
  }

  private LinkedBlockingQueue<Integer> getStateQueue(String id) {
    synchronized (downloadStates) {
      @Nullable LinkedBlockingQueue<Integer> stateQueue = downloadStates.get(id);
      if (stateQueue == null) {
        stateQueue = new LinkedBlockingQueue<>();
        downloadStates.put(id, stateQueue);
      }
      return stateQueue;
    }
  }
}