/**
   * Method that load the gles texture and apply to the requestor frame (which includes fix the
   * aspect ratio and/or effects and borders)
   *
   * @param requestor The requestor target
   * @param ti The original texture information (the one with the bitmap one)
   */
  private void applyToRequestor(TextureRequestor requestor, GLESTextureInfo ti) {
    // Transform requestor dimensions to screen dimensions
    RectF dimens = requestor.getRequestorDimensions();
    Rect pixels =
        new Rect(
            0,
            0,
            (int) (mScreenDimensions.width() * dimens.width() / 2),
            (int) (mScreenDimensions.height() * dimens.height() / 2));

    final Disposition disposition = requestor.getDisposition();
    synchronized (mEffectsSync) {
      if (disposition.hasFlag(Disposition.EFFECT_FLAG)) {
        ti.effect = mEffects.getNextEffect();
      }
      if (disposition.hasFlag(Disposition.BORDER_FLAG)) {
        ti.border = mBorders.getNextBorder();
      }
    }

    // Check if we have to apply any correction to the image
    GLESTextureInfo dst;
    if (ti.bitmap != null && Preferences.General.isFixAspectRatio(mContext)) {

      // Create a texture of power of two here to avoid scaling the bitmap twice
      int w = pixels.width();
      int h = pixels.height();
      if (!BitmapUtils.isPowerOfTwo(w, h)
          && PreferencesProvider.Preferences.General.isPowerOfTwo(mContext)) {
        w = h = BitmapUtils.calculateUpperPowerOfTwo(Math.min(w, h));
      }

      // Create a thumbnail of the image
      Bitmap thumb = BitmapUtils.createScaledBitmap(ti.bitmap, w, h, BitmapUtils.ScalingLogic.CROP);
      if (!thumb.equals(ti.bitmap)) {
        ti.bitmap.recycle();
      }
      dst = GLESUtil.loadTexture(mContext, thumb, ti.effect, ti.border, pixels);
    } else {
      // Load the texture without any correction
      dst = GLESUtil.loadTexture(mContext, ti.bitmap, ti.effect, ti.border, pixels);
    }

    // Swap references
    ti.bitmap = dst.bitmap;
    ti.handle = dst.handle;
    ti.effect = null;
    ti.border = null;
    dst.handle = 0;
    dst.bitmap = null;

    // And notify to the requestor
    requestor.setTextureHandle(ti);

    // Clean up memory
    if (ti.bitmap != null) {
      ti.bitmap.recycle();
      ti.bitmap = null;
    }
  }
    /** {@inheritDoc} */
    @Override
    public void run() {
      try {
        // Load the bitmap and create a fake gles information
        ti = GLESUtil.loadFadeTexture(mImage, mDimensions);

        boolean enqueue;
        synchronized (mSync) {
          enqueue = mPendingRequests.size() == 0;
        }
        synchronized (mSync) {
          // Notify the new images to all pending frames
          if (!enqueue) {
            // Invalid textures are also reported, so requestor can handle it
            TextureRequestor requestor = mPendingRequests.remove(0);
            applyToRequestor(requestor, ti);

          } else {
            // Add to the queue (only valid textures)
            if (ti.bitmap != null) {
              mQueue.insert(ti);
            }
          }
        }

      } catch (Throwable e) {
        Log.e(TAG, "Something was wrong loading the texture: " + mImage.getAbsolutePath(), e);

      } finally {
        // Notify that we have a new image
        synchronized (mWait) {
          mWait.notify();
        }
      }
    }
  /**
   * Method that removes all the textures from the queue
   *
   * @param reload Forces a reload of the queue
   */
  public void emptyTextureQueue(boolean reload) {
    synchronized (mSync) {
      // Recycle the textures
      try {
        List<GLESTextureInfo> all = mQueue.removeAll();
        for (GLESTextureInfo info : all) {
          if (GLES20.glIsTexture(info.handle)) {
            int[] textures = new int[] {info.handle};
            if (GLESUtil.DEBUG_GL_MEMOBJS) {
              Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + info.handle + "]");
            }
            GLES20.glDeleteTextures(1, textures, 0);
            GLESUtil.glesCheckError("glDeleteTextures");
          }
          // Return the bitmap
          info.bitmap.recycle();
          info.bitmap = null;
        }
      } catch (EmptyQueueException eqex) {
        // Ignore
      }

      // Remove all pictures in the queue
      try {
        mQueue.removeAll();
      } catch (EmptyQueueException ex) {
        // Ignore
      }

      // Reload the queue
      if (reload) {
        synchronized (mBackgroundTask.mLoadSync) {
          mBackgroundTask.resetAvailableImages();
          mBackgroundTask.mLoadSync.notify();
        }
      }
    }
  }