public static void mkdir(
      final HybridFile parentFile,
      @NonNull final HybridFile file,
      final Context context,
      final boolean rootMode,
      @NonNull final ErrorCallBack errorCallBack) {

    new AsyncTask<Void, Void, Void>() {

      private DataUtils dataUtils = DataUtils.getInstance();

      private Function<DocumentFile, Void> safCreateDirectory =
          input -> {
            if (input != null && input.isDirectory()) {
              boolean result = false;
              try {
                result = input.createDirectory(file.getName(context)) != null;
              } catch (Exception e) {
                LOG.warn("Failed to make directory", e);
              }
              errorCallBack.done(file, result);
            } else errorCallBack.done(file, false);
            return null;
          };

      @Override
      protected Void doInBackground(Void... params) {
        // checking whether filename is valid or a recursive call possible
        if (!Operations.isFileNameValid(file.getName(context))) {
          errorCallBack.invalidName(file);
          return null;
        }

        if (file.exists()) {
          errorCallBack.exists(file);
          return null;
        }

        // Android data directory, prohibit create directory
        if (file.isAndroidDataDir()) {
          errorCallBack.done(file, false);
          return null;
        }

        if (file.isSftp() || file.isFtp()) {
          file.mkdir(context);
          /*
          FIXME: throw Exceptions from HybridFile.mkdir() so errorCallback can throw Exceptions
           here
           */
          errorCallBack.done(file, true);
          return null;
        }
        if (file.isSmb()) {
          try {
            file.getSmbFile(2000).mkdirs();
          } catch (SmbException e) {
            LOG.warn("failed to make smb directories", e);
            errorCallBack.done(file, false);
            return null;
          }
          errorCallBack.done(file, file.exists());
          return null;
        }
        if (file.isOtgFile()) {
          if (checkOtgNewFileExists(file, context)) {
            errorCallBack.exists(file);
            return null;
          }
          safCreateDirectory.apply(OTGUtil.getDocumentFile(parentFile.getPath(), context, false));
          return null;
        }
        if (file.isDocumentFile()) {
          if (checkDocumentFileNewFileExists(file, context)) {
            errorCallBack.exists(file);
            return null;
          }
          safCreateDirectory.apply(
              OTGUtil.getDocumentFile(
                  parentFile.getPath(),
                  SafRootHolder.getUriRoot(),
                  context,
                  OpenMode.DOCUMENT_FILE,
                  false));
          return null;
        } else if (file.isDropBoxFile()) {
          CloudStorage cloudStorageDropbox = dataUtils.getAccount(OpenMode.DROPBOX);
          try {
            cloudStorageDropbox.createFolder(CloudUtil.stripPath(OpenMode.DROPBOX, file.getPath()));
            errorCallBack.done(file, true);
          } catch (Exception e) {
            LOG.warn("failed to make directory in cloud connection", e);
            errorCallBack.done(file, false);
          }
        } else if (file.isBoxFile()) {
          CloudStorage cloudStorageBox = dataUtils.getAccount(OpenMode.BOX);
          try {
            cloudStorageBox.createFolder(CloudUtil.stripPath(OpenMode.BOX, file.getPath()));
            errorCallBack.done(file, true);
          } catch (Exception e) {
            LOG.warn("failed to make directory in cloud connection", e);
            errorCallBack.done(file, false);
          }
        } else if (file.isOneDriveFile()) {
          CloudStorage cloudStorageOneDrive = dataUtils.getAccount(OpenMode.ONEDRIVE);
          try {
            cloudStorageOneDrive.createFolder(
                CloudUtil.stripPath(OpenMode.ONEDRIVE, file.getPath()));
            errorCallBack.done(file, true);
          } catch (Exception e) {
            LOG.warn("failed to make directory in cloud connection", e);
            errorCallBack.done(file, false);
          }
        } else if (file.isGoogleDriveFile()) {
          CloudStorage cloudStorageGdrive = dataUtils.getAccount(OpenMode.GDRIVE);
          try {
            cloudStorageGdrive.createFolder(CloudUtil.stripPath(OpenMode.GDRIVE, file.getPath()));
            errorCallBack.done(file, true);
          } catch (Exception e) {
            LOG.warn("failed to make directory in cloud connection", e);
            errorCallBack.done(file, false);
          }
        } else {
          if (file.isLocal() || file.isRoot()) {
            int mode = checkFolder(new File(file.getParent(context)), context);
            if (mode == 2) {
              errorCallBack.launchSAF(file);
              return null;
            }
            if (mode == 1 || mode == 0) MakeDirectoryOperation.mkdir(file.getFile(), context);
            if (!file.exists() && rootMode) {
              file.setMode(OpenMode.ROOT);
              if (file.exists()) errorCallBack.exists(file);
              try {
                MakeDirectoryCommand.INSTANCE.makeDirectory(
                    file.getParent(context), file.getName(context));
              } catch (ShellNotRunningException e) {
                LOG.warn("failed to make directory in local filesystem", e);
              }
              errorCallBack.done(file, file.exists());
              return null;
            }
            errorCallBack.done(file, file.exists());
            return null;
          }

          errorCallBack.done(file, file.exists());
        }
        return null;
      }
    }.executeOnExecutor(executor);
  }
@Test
  public void testMkdirNewFolderSameNameAsCurrentFolder() throws InterruptedException {
    File newFolder = new File(storageRoot, "test");
    HybridFile newFolderHF = new HybridFile(OpenMode.FILE, newFolder.getAbsolutePath());

    CountDownLatch waiter1 = new CountDownLatch(1);
    Operations.mkdir(
        newFolderHF,
        newFolderHF,
        ApplicationProvider.getApplicationContext(),
        false,
        new AbstractErrorCallback() {
          @Override
          public void done(HybridFile hFile, boolean b) {
            waiter1.countDown();
          }
        });
    waiter1.await();
    assertTrue(newFolder.exists());

    File newFolder2 = new File(newFolder, "test");
    HybridFile newFolder2HF = new HybridFile(OpenMode.FILE, newFolder2.getAbsolutePath());
    CountDownLatch waiter2 = new CountDownLatch(1);
    Operations.mkdir(
        newFolder2HF,
        newFolder2HF,
        ApplicationProvider.getApplicationContext(),
        false,
        new AbstractErrorCallback() {
          @Override
          public void done(HybridFile hFile, boolean b) {
            waiter2.countDown();
          }
        });
    waiter2.await();
    assertTrue(newFolder2.exists());

    CountDownLatch waiter3 = new CountDownLatch(1);
    AtomicBoolean assertFlag = new AtomicBoolean(false);
    Operations.mkdir(
        newFolder2HF,
        newFolder2HF,
        ApplicationProvider.getApplicationContext(),
        false,
        new AbstractErrorCallback() {
          @Override
          public void exists(HybridFile file) {
            assertFlag.set(true);
            waiter3.countDown();
          }
        });
    waiter3.await();
    assertTrue(assertFlag.get());
  }