/** Method that destroy the references of this class */
  public void recycle() {
    // Destroy the media discovery task
    mPictureDiscoverer.recycle();
    synchronized (mEffectsSync) {
      if (mEffects != null) {
        mEffects.release();
      }
      if (mBorders != null) {
        mBorders.release();
      }
    }

    // Destroy the background task
    if (mBackgroundTask != null) {
      mBackgroundTask.mRun = false;
      try {
        synchronized (mBackgroundTask.mLoadSync) {
          mBackgroundTask.interrupt();
        }
      } catch (Exception e) {
        // Ignore
      }
    }
    mBackgroundTask = null;
  }
 /** {@inheritDoc} */
 @Override
 public void onStartMediaDiscovered(boolean userRequest) {
   // No images but thread should start here to received partial data
   this.mStatus = 0; // Loading
   if (mBackgroundTask != null) {
     mBackgroundTask.setAvailableImages(new File[] {});
     if (!mBackgroundTask.mRun) {
       mBackgroundTask.start();
     } else {
       synchronized (mBackgroundTask.mLoadSync) {
         mBackgroundTask.mLoadSync.notify();
       }
     }
   }
 }
  /** {@inheritDoc} */
  @Override
  @SuppressWarnings("boxing")
  public void onEndMediaDiscovered(File[] images, boolean userRequest) {
    // Now we have the paths of the images to use. Notify to the thread to
    // load pictures in background
    if (mBackgroundTask != null) {
      mBackgroundTask.setAvailableImages(images);
      if (images != null && images.length > 0) {
        mFirstLoad = false;
      }
      synchronized (mBackgroundTask.mLoadSync) {
        mBackgroundTask.mLoadSync.notify();
      }
      this.mStatus = 1; // Loaded

      // Audit
      int found = images == null ? 0 : images.length;
      Log.d(TAG, "Media picture data reloaded: " + found + " images found.");
      if (userRequest) {
        CharSequence msg =
            String.format(
                mContext
                    .getResources()
                    .getQuantityText(R.plurals.msg_media_reload_complete, found)
                    .toString(),
                found);
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
      }
    } else {
      this.mStatus = 2; // Error
    }
  }
  /**
   * Constructor of <code>PhotoPhaseTextureManager</code>
   *
   * @param ctx The current context
   * @param effectCtx The current effect context
   * @param dispatcher The GLES dispatcher
   * @param requestors The number of requestors
   * @param screenDimensions The screen dimensions
   */
  public PhotoPhaseTextureManager(
      final Context ctx,
      final Handler handler,
      final EffectContext effectCtx,
      GLESSurfaceDispatcher dispatcher,
      int requestors,
      Rect screenDimensions) {
    super();
    mContext = ctx;
    mHandler = handler;
    mEffects = new Effects(ctx, effectCtx);
    mBorders = new Borders(ctx, effectCtx);
    mDispatcher = dispatcher;
    mScreenDimensions = screenDimensions;
    mDimensions =
        screenDimensions; // For now, use the screen dimensions as the preferred dimensions for
                          // bitmaps
    mSync = new Object();
    mPendingRequests = new ArrayList<>(requestors);
    mPictureDiscoverer = new MediaPictureDiscoverer(mContext);

    // Run the media discovery thread
    mBackgroundTask = new BackgroundPictureLoaderThread();
    mBackgroundTask.mTaskPaused = false;
    reloadMedia(false);
  }
 /**
  * Method that pauses the internal threads
  *
  * @param pause If the thread is paused (true) or resumed (false)
  */
 public synchronized void setPause(boolean pause) {
   synchronized (mBackgroundTask.mLoadSync) {
     mBackgroundTask.mTaskPaused = pause;
     if (!mBackgroundTask.mTaskPaused) {
       mBackgroundTask.mLoadSync.notify();
     }
   }
 }
 /** {@inheritDoc} */
 @Override
 public void onPartialMediaDiscovered(File[] images, boolean userRequest) {
   if (mBackgroundTask != null) {
     // In order to continue with the last media shown, we need all the
     // images to process them
     if (!Preferences.Media.isRememberLastMediaShown(mContext)) {
       mBackgroundTask.setPartialAvailableImages(images);
     }
   }
 }
  /**
   * 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();
        }
      }
    }
  }