package org.robolectric.shadows;

import android.app.QueuedWork;
import android.os.Build;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;

@Implements(value = QueuedWork.class, isInAndroidSdk = false)
public class ShadowQueuedWork {

  @Resetter
  public static void reset() {
    QueuedWork.waitToFinish();
    if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) {
      ReflectionHelpers.setStaticField(QueuedWork.class, "sHandler", null);
    } else {
      ReflectionHelpers.setStaticField(QueuedWork.class, "sSingleThreadExecutor", null);
    }
  }
}

package org.robolectric.shadows;

import android.app.QueuedWork;
import android.os.Build;
import android.os.Handler;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;

import java.util.List;

@Implements(value = QueuedWork.class, isInAndroidSdk = false)
public class ShadowQueuedWork {

  @Resetter
  public static void reset() {
    if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.O) {
      resetStateApi26();
    } else {
      QueuedWork.waitToFinish();
      ReflectionHelpers.setStaticField(QueuedWork.class, "sSingleThreadExecutor", null);
    }
  }

  private static void resetStateApi26() {
    Handler queuedWorkHandler = ReflectionHelpers.getStaticField(QueuedWork.class, "sHandler");
    if (queuedWorkHandler != null) {
      queuedWorkHandler.removeCallbacksAndMessages(null);
    }
    ((List) ReflectionHelpers.getStaticField(QueuedWork.class, "sFinishers")).clear();
    ((List) ReflectionHelpers.getStaticField(QueuedWork.class, "sWork")).clear();
    ReflectionHelpers.setStaticField(QueuedWork.class, "mNumWaits", 0);
  }
}

Update QueuedWork Resetter for API 26
Update QueuedWork Resetter for API 26

This is part of an effort to resolve deadlocks that may occur with
SharedPreferences on SDK 26.

In API 26, the implementation of QueuedWork changed from a
ThreadPoolExecutor to a Handler combined with two lists of Runnables. In
this API level, setting the `sHandler` static variable to null led to a
memory leak. Each test that called `QueuedWork.getHandler()` caused a
new Handler to be created and added to `ShadowLooper.loopingLoopers`.

Because the Handler and Runnable lists are being cleared, there's no
need to call `QueuedWork.waitToFinish()` in API 26.
