/**
   * Acquire the lock so that the scene can be acted upon.
   *
   * <p>This returns null if the lock was just acquired, otherwise it returns {@link
   * Result.Status#SUCCESS} if the lock already belonged to that thread, or another instance (see
   * {@link Result#getStatus()}) if an error occurred.
   *
   * @param timeout the time to wait if another rendering is happening.
   * @return null if the lock was just acquire or another result depending on the state.
   * @throws IllegalStateException if the current context is different than the one owned by the
   *     scene.
   */
  private Result acquireLock(long timeout) {
    ReentrantLock lock = Bridge.getLock();
    if (!lock.isHeldByCurrentThread()) {
      try {
        boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);

        if (!acquired) {
          return ERROR_TIMEOUT.createResult();
        }
      } catch (InterruptedException e) {
        return ERROR_LOCK_INTERRUPTED.createResult();
      }
    } else {
      // This thread holds the lock already. Checks that this wasn't for a different context.
      // If this is called by init, mContext will be null and so should sCurrentContext
      // anyway
      if (mContext != sCurrentContext) {
        throw new IllegalStateException(
            "Acquiring different scenes from same thread without releases");
      }
      return SUCCESS.createResult();
    }

    return null;
  }
  /**
   * Prepares the scene for action.
   *
   * <p>This call is blocking if another rendering/inflating is currently happening, and will return
   * whether the preparation worked.
   *
   * <p>The preparation can fail if another rendering took too long and the timeout was elapsed.
   *
   * <p>More than one call to this from the same thread will have no effect and will return {@link
   * Result.Status#SUCCESS}.
   *
   * <p>After scene actions have taken place, only one call to {@link #release()} must be done.
   *
   * @param timeout the time to wait if another rendering is happening.
   * @return whether the scene was prepared
   * @see #release()
   * @throws IllegalStateException if {@link #init(long)} was never called.
   */
  public Result acquire(long timeout) {
    if (mContext == null) {
      throw new IllegalStateException("After scene creation, #init() must be called");
    }

    // acquire the lock. if the result is null, lock was just acquired, otherwise, return
    // the result.
    Result result = acquireLock(timeout);
    if (result != null) {
      return result;
    }

    setUp();

    return SUCCESS.createResult();
  }
  /**
   * Initializes and acquires the scene, creating various Android objects such as context, inflater,
   * and parser.
   *
   * @param timeout the time to wait if another rendering is happening.
   * @return whether the scene was prepared
   * @see #acquire(long)
   * @see #release()
   */
  public Result init(long timeout) {
    // acquire the lock. if the result is null, lock was just acquired, otherwise, return
    // the result.
    Result result = acquireLock(timeout);
    if (result != null) {
      return result;
    }

    // setup the ParserFactory
    ParserFactory.setParserFactory(mParams.getLayoutlibCallback().getParserFactory());

    HardwareConfig hardwareConfig = mParams.getHardwareConfig();

    // setup the display Metrics.
    DisplayMetrics metrics = new DisplayMetrics();
    metrics.densityDpi = metrics.noncompatDensityDpi = hardwareConfig.getDensity().getDpiValue();

    metrics.density =
        metrics.noncompatDensity = metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;

    metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;

    metrics.widthPixels = metrics.noncompatWidthPixels = hardwareConfig.getScreenWidth();
    metrics.heightPixels = metrics.noncompatHeightPixels = hardwareConfig.getScreenHeight();
    metrics.xdpi = metrics.noncompatXdpi = hardwareConfig.getXdpi();
    metrics.ydpi = metrics.noncompatYdpi = hardwareConfig.getYdpi();

    RenderResources resources = mParams.getResources();

    // build the context
    mContext =
        new BridgeContext(
            mParams.getProjectKey(),
            metrics,
            resources,
            mParams.getAssets(),
            mParams.getLayoutlibCallback(),
            getConfiguration(),
            mParams.getTargetSdkVersion(),
            mParams.isRtlSupported());

    setUp();

    return SUCCESS.createResult();
  }