private final int copyFiles(File[] list, Uri dest) throws InterruptedException {
      File file = null;
      for (int i = 0; i < list.length; i++) {
        InputStream is = null;
        OutputStream os = null;
        file = list[i];
        if (file == null) {
          error(ctx.getString(R.string.unkn_err));
          break;
        }
        Uri dest_uri = null;
        try {
          if (isStopReq()) {
            error(ctx.getString(R.string.canceled));
            break;
          }
          String fn = file.getName();
          String to_append = "%2f" + Utils.escapePath(fn);
          dest_uri = dest.buildUpon().encodedPath(dest.getEncodedPath() + to_append).build();
          String mime = getMime(dest_uri);
          if (file.isDirectory()) {
            if (depth++ > 40) {
              error(ctx.getString(R.string.too_deep_hierarchy));
              break;
            }
            if (mime != null) {
              if (!Document.MIME_TYPE_DIR.equals(mime)) {
                error(ctx.getString(R.string.cant_md));
                break;
              }
            } else {
              DocumentsContract.createDocument(cr, dest, Document.MIME_TYPE_DIR, fn);
            }
            copyFiles(file.listFiles(), dest_uri);
            if (errMsg != null) break;
            depth--;
            counter++;
          } else {
            if (mime != null) {
              int res = askOnFileExist(ctx.getString(R.string.file_exist, fn), commander);
              if (res == Commander.SKIP) continue;
              if (res == Commander.ABORT) break;
              if (res == Commander.REPLACE) {
                File dest_file = new File(getPath(dest_uri, false));
                if (dest_file.equals(file)) {
                  Log.w(TAG, "Not going to copy file to itself");
                  continue;
                }
                Log.v(TAG, "Overwritting file " + fn);
                DocumentsContract.deleteDocument(cr, dest_uri);
              }
            } else mime = Utils.getMimeByExt(Utils.getFileExt(fn));
            dest_uri = DocumentsContract.createDocument(cr, dest, mime, fn);
            if (dest_uri == null) {
              error(ctx.getString(R.string.cant_create, fn, ""));
              break;
            }
            String dest_path = dest_uri.getPath();
            if (dest_path.indexOf(fn, dest_path.length() - fn.length() - 1) < 0) // SAF suxx
            dest_uri = DocumentsContract.renameDocument(cr, dest_uri, fn);

            is = new FileInputStream(file);
            os = cr.openOutputStream(dest_uri);
            long copied = 0, size = file.length();

            long start_time = 0;
            int speed = 0;
            int so_far = (int) (totalBytes * conv);

            String sz_s = Utils.getHumanSize(size);
            int fnl = fn.length();
            String rep_s =
                ctx.getString(
                    R.string.copying, fnl > CUT_LEN ? "\u2026" + fn.substring(fnl - CUT_LEN) : fn);
            int n = 0;
            long nn = 0;

            while (true) {
              if (nn == 0) {
                start_time = System.currentTimeMillis();
                sendProgress(
                    rep_s + sizeOfsize(copied, sz_s), so_far, (int) (totalBytes * conv), speed);
              }
              n = is.read(buf);
              if (n < 0) {
                long time_delta = System.currentTimeMillis() - start_time;
                if (time_delta > 0) {
                  speed = (int) (MILLI * nn / time_delta);
                  sendProgress(
                      rep_s + sizeOfsize(copied, sz_s), so_far, (int) (totalBytes * conv), speed);
                }
                break;
              }
              os.write(buf, 0, n);
              nn += n;
              copied += n;
              totalBytes += n;
              if (isStopReq()) {
                Log.d(TAG, "Interrupted!");
                error(ctx.getString(R.string.canceled));
                return counter;
              }
              long time_delta = System.currentTimeMillis() - start_time;
              if (time_delta > DELAY) {
                speed = (int) (MILLI * nn / time_delta);
                // Log.v( TAG, "bytes: " + nn + " time: " + time_delta + " speed: " + speed );
                nn = 0;
              }
            }
            is.close();
            os.close();
            is = null;
            os = null;
            /*
            ContentValues cv = new ContentValues();
            cv.put( Document.COLUMN_LAST_MODIFIED, file.lastModified() );
            cr.update( dest_uri, cv, null, null ); //throws..
            */
            if (i >= list.length - 1)
              sendProgress(
                  ctx.getString(R.string.copied_f, fn) + sizeOfsize(copied, sz_s),
                  (int) (totalBytes * conv));
            counter++;
          }
          if (move) {
            if (!file.delete()) {
              sendProgress(ctx.getString(R.string.cant_del, fn), -1);
              delerr_counter++;
            }
          }
        } catch (Exception e) {
          Log.e(TAG, "", e);
          error(ctx.getString(R.string.rtexcept, file.getAbsolutePath(), e.getMessage()));
        } finally {
          try {
            if (is != null) is.close();
            if (os != null) os.close();
          } catch (IOException e) {
            error(ctx.getString(R.string.acc_err, file.getAbsolutePath(), e.getMessage()));
          }
        }
      }
      return counter;
    }
    private final int copyFiles(Item[] l, File dest) throws Exception {
      if (l == null) return 0;
      int cnt = 0;
      int num = l.length;
      for (int i = 0; i < num; i++) {
        sleep(1);
        if (isStopReq()) throw new Exception(s(R.string.canceled));
        Item item = l[i];
        String fn = item.name;
        sendProgress(ctx.getString(R.string.copying, fn), 0);
        File dest_file = new File(dest, fn);
        Uri u = (Uri) item.origin;
        boolean ok = false;
        if (item.dir) {
          if (!dest_file.exists()) dest_file.mkdir();
          ArrayList<SAFItem> tmp_list = getChildren(u);
          SAFItem[] sub_items = new SAFItem[tmp_list.size()];
          tmp_list.toArray(sub_items);
          cnt += copyFiles(sub_items, dest_file);
          if (errMsg != null) break;
          ok = true;
        } else {
          if (dest_file.exists()) {
            int res =
                askOnFileExist(
                    owner.ctx.getString(R.string.file_exist, dest_file.getAbsolutePath()),
                    owner.commander);
            if (res == Commander.ABORT) {
              error(owner.ctx.getString(R.string.interrupted));
              break;
            }
            if (res == Commander.SKIP) continue;
            if (res == Commander.REPLACE) {
              if (!dest_file.delete()) {
                error(owner.ctx.getString(R.string.cant_del, dest_file.getAbsoluteFile()));
                break;
              }
            }
          }
          int fnl = fn.length();
          String rep_s =
              owner.ctx.getString(
                  R.string.copying, fnl > CUT_LEN ? "\u2026" + fn.substring(fnl - CUT_LEN) : fn);

          long copied = 0, size = item.size;
          String sz_s = Utils.getHumanSize(size, false);
          double conv = 100. / size;
          int n;
          OutputStream os = null;
          InputStream is = null;
          try {
            os = new FileOutputStream(dest_file);
            is = cr.openInputStream(u);
            while ((n = is.read(buf)) != -1) {
              os.write(buf, 0, n);
              copied += n;
              sendProgress(rep_s + sizeOfsize(copied, sz_s), (int) (copied * conv));
              Thread.sleep(1);
            }
            ok = true;
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            if (is != null) is.close();
            if (os != null) os.close();
          }
          try {
            dest_file.setLastModified(item.date.getTime());
          } catch (Exception e) {
          }
        }
        if (move && ok) DocumentsContract.deleteDocument(cr, u);
        cnt++;
      }
      return cnt;
    }