/**
   * Delete a file. May be even on external SD card.
   *
   * @param file the file to be deleted.
   * @return True if successfully deleted.
   */
  public static final boolean deleteFile(@NonNull final File file, Context context) {
    // First try the normal deletion.
    boolean fileDelete = deleteFilesInFolder(file, context);
    if (file.delete() || fileDelete) return true;

    // Try with Storage Access Framework.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
        && FileUtil.isOnExtSdCard(file, context)) {

      DocumentFile document = getDocumentFile(file, false, context);
      return document.delete();
    }

    // Try the Kitkat workaround.
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
      ContentResolver resolver = context.getContentResolver();

      try {
        Uri uri = MediaStoreUtil.getUriFromFile(file.getAbsolutePath(), context);
        resolver.delete(uri, null, null);
        return !file.exists();
      } catch (Exception e) {
        Log.e("AmazeFileUtils", "Error when deleting file " + file.getAbsolutePath(), e);
        return false;
      }
    }

    return !file.exists();
  }
  /**
   * Copy a file. The target file may even be on external SD card for Kitkat.
   *
   * @param source The source file
   * @param target The target file
   * @return true if the copying was successful.
   */
  @SuppressWarnings("null")
  public static boolean copyFile(final File source, final File target, Context context) {
    FileInputStream inStream = null;
    OutputStream outStream = null;
    FileChannel inChannel = null;
    FileChannel outChannel = null;
    try {
      inStream = new FileInputStream(source);

      // First try the normal way
      if (isWritable(target)) {
        // standard way
        outStream = new FileOutputStream(target);
        inChannel = inStream.getChannel();
        outChannel = ((FileOutputStream) outStream).getChannel();
        inChannel.transferTo(0, inChannel.size(), outChannel);
      } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          // Storage Access Framework
          DocumentFile targetDocument = getDocumentFile(target, false, context);
          outStream = context.getContentResolver().openOutputStream(targetDocument.getUri());
        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
          // Workaround for Kitkat ext SD card
          Uri uri = MediaStoreUtil.getUriFromFile(target.getAbsolutePath(), context);
          outStream = context.getContentResolver().openOutputStream(uri);
        } else {
          return false;
        }

        if (outStream != null) {
          // Both for SAF and for Kitkat, write to output stream.
          byte[] buffer = new byte[16384]; // MAGIC_NUMBER
          int bytesRead;
          while ((bytesRead = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, bytesRead);
          }
        }
      }
    } catch (Exception e) {
      Log.e(
          "AmazeFileUtils",
          "Error when copying file from "
              + source.getAbsolutePath()
              + " to "
              + target.getAbsolutePath(),
          e);
      return false;
    } finally {
      try {
        inStream.close();
      } catch (Exception e) {
        // ignore exception
      }
      try {
        outStream.close();
      } catch (Exception e) {
        // ignore exception
      }
      try {
        inChannel.close();
      } catch (Exception e) {
        // ignore exception
      }
      try {
        outChannel.close();
      } catch (Exception e) {
        // ignore exception
      }
    }
    return true;
  }