public class

ActivityFinisherRunListener

extends RunListener

 java.lang.Object

↳RunListener

↳androidx.test.internal.runner.listener.ActivityFinisherRunListener

Gradle dependencies

compile group: 'androidx.test', name: 'runner', version: '1.6.2'

  • groupId: androidx.test
  • artifactId: runner
  • version: 1.6.2

Artifact androidx.test:runner:1.6.2 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.test:runner com.android.support.test:runner

Overview

Ensures that no activities are running when a test method starts and that no activities are still running when it ends.

Summary

Constructors
publicActivityFinisherRunListener(Instrumentation instrumentation, java.lang.Runnable finisher, java.lang.Runnable waitForActivitiesToStopRunnable)

Methods
public voidtestFinished(Description description)

public voidtestStarted(Description description)

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

Constructors

public ActivityFinisherRunListener(Instrumentation instrumentation, java.lang.Runnable finisher, java.lang.Runnable waitForActivitiesToStopRunnable)

Methods

public void testStarted(Description description)

public void testFinished(Description description)

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.test.internal.runner.listener;

import static androidx.test.internal.util.Checks.checkNotNull;

import android.app.Instrumentation;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.test.internal.runner.InstrumentationConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.runner.Description;
import org.junit.runner.notification.RunListener;

/**
 * Ensures that no activities are running when a test method starts and that no activities are still
 * running when it ends.
 */
public class ActivityFinisherRunListener extends RunListener {
  private final Instrumentation instrumentation;
  private final NotifyingRunnable activityFinisher;
  private final Runnable waitForActivitiesToStopRunnable;
  private final Handler handler;

  public ActivityFinisherRunListener(
      Instrumentation instrumentation,
      Runnable finisher,
      Runnable waitForActivitiesToStopRunnable) {
    this.instrumentation = checkNotNull(instrumentation);
    this.activityFinisher = new NotifyingRunnable(checkNotNull(finisher));
    this.waitForActivitiesToStopRunnable = checkNotNull(waitForActivitiesToStopRunnable);
    this.handler = new Handler(Looper.getMainLooper());
  }

  @Override
  public void testStarted(Description description) throws Exception {
    runActivityFinisher();
    waitForActivitiesToStopRunnable.run();
  }

  private void runActivityFinisher() throws InterruptedException {
    handler.post(activityFinisher);
    // wait for the finisher to run, but don't wait forever since this will deadlock and timeout
    // the test if main thread is blocked
    if (!activityFinisher.await(2, TimeUnit.SECONDS)) {
      Log.w(
          "AFRunListener",
          "activity finisher did not run within 2 seconds. Is main thread blocked?");
      // remove the finisher to prevent potential test pollution where activities will be finished
      // mid-test
      handler.removeCallbacks(activityFinisher);
    }
  }

  @Override
  public void testFinished(Description description) throws Exception {
    InstrumentationConnection.getInstance().requestRemoteInstancesActivityCleanup();
    runActivityFinisher();
    waitForActivitiesToStopRunnable.run();
  }

  private static class NotifyingRunnable implements Runnable {

    private final Runnable wrappedRunnable;
    private final CountDownLatch latch = new CountDownLatch(1);

    NotifyingRunnable(Runnable wrappedRunnable) {
      this.wrappedRunnable = wrappedRunnable;
    }

    @Override
    public void run() {
      wrappedRunnable.run();
      latch.countDown();
    }

    public boolean await(long time, TimeUnit unit) throws InterruptedException {
      return latch.await(time, unit);
    }
  }
}