@Override
  @Implementation
  public boolean equals(Object object) {
    if (!(object instanceof AccessibilityEvent)) {
      return false;
    }

    final AccessibilityEvent event = (AccessibilityEvent) object;
    final ShadowAccessibilityEvent otherShadow =
        (ShadowAccessibilityEvent) ShadowExtractor.extract(event);

    boolean areEqual = (eventType == otherShadow.eventType);
    areEqual &= (enabled == otherShadow.enabled);
    areEqual &= TextUtils.equals(contentDescription, otherShadow.contentDescription);
    areEqual &= TextUtils.equals(packageName, otherShadow.packageName);
    areEqual &= TextUtils.equals(className, otherShadow.className);
    boolean parcelableDataEqual = false;
    if (getParcelableData() == null && otherShadow.getParcelableData() == null) {
      parcelableDataEqual = true;
    } else if (getParcelableData().equals(otherShadow.getParcelableData())) {
      parcelableDataEqual = true;
    }
    areEqual &= parcelableDataEqual;

    return areEqual;
  }
  @Implementation
  public static AccessibilityEvent obtain(AccessibilityEvent event) {
    ShadowAccessibilityEvent shadowEvent =
        ((ShadowAccessibilityEvent) ShadowExtractor.extract(event));
    AccessibilityEvent obtainedInstance = shadowEvent.getClone();

    sAllocationCount++;
    StrictEqualityEventWrapper wrapper = new StrictEqualityEventWrapper(obtainedInstance);
    obtainedInstances.put(wrapper, Thread.currentThread().getStackTrace());
    orderedInstances.put(sAllocationCount, wrapper);
    return obtainedInstance;
  }
  @Implementation
  public static AccessibilityEvent obtain(int eventType) {
    // We explicitly avoid allocating the AccessibilityEvent from the actual pool by using
    // the private constructor. Not doing so affects test suites which use both shadow and
    // non-shadow objects.
    final AccessibilityEvent obtainedInstance =
        ReflectionHelpers.callConstructor(AccessibilityEvent.class);
    final ShadowAccessibilityEvent shadowObtained =
        ((ShadowAccessibilityEvent) ShadowExtractor.extract(obtainedInstance));

    sAllocationCount++;
    StrictEqualityEventWrapper wrapper = new StrictEqualityEventWrapper(obtainedInstance);
    obtainedInstances.put(wrapper, Thread.currentThread().getStackTrace());
    orderedInstances.put(sAllocationCount, wrapper);
    shadowObtained.eventType = eventType;
    return obtainedInstance;
  }
  /**
   * Check for leaked objects that were {@code obtain}ed but never {@code recycle}d.
   *
   * @param printUnrecycledEventsToSystemErr - if true, stack traces of calls to {@code obtain} that
   *     lack matching calls to {@code recycle} are dumped to System.err.
   * @return {@code true} if there are unrecycled events
   */
  public static boolean areThereUnrecycledEvents(boolean printUnrecycledEventsToSystemErr) {
    if (printUnrecycledEventsToSystemErr) {
      for (final StrictEqualityEventWrapper wrapper : obtainedInstances.keySet()) {
        final ShadowAccessibilityEvent shadow =
            ((ShadowAccessibilityEvent) ShadowExtractor.extract(wrapper.mEvent));

        System.err.println(
            String.format(
                "Leaked AccessibilityEvent. Stack trace of allocation:",
                shadow.getContentDescription()));
        for (final StackTraceElement stackTraceElement : obtainedInstances.get(wrapper)) {
          System.err.println(stackTraceElement.toString());
        }
      }
    }

    return (obtainedInstances.size() != 0);
  }
  /** @return A shallow copy. */
  private AccessibilityEvent getClone() {
    // We explicitly avoid allocating the AccessibilityEvent from the actual pool by using
    // the private constructor. Not doing so affects test suites which use both shadow and
    // non-shadow objects.
    final AccessibilityEvent newEvent = ReflectionHelpers.callConstructor(AccessibilityEvent.class);
    final ShadowAccessibilityEvent newShadow =
        (ShadowAccessibilityEvent) ShadowExtractor.extract(newEvent);

    newShadow.eventType = eventType;
    newShadow.contentDescription = contentDescription;
    newShadow.packageName = packageName;
    newShadow.className = className;
    newShadow.enabled = enabled;
    newShadow.setParcelableData(getParcelableData());

    return newEvent;
  }