@WorkerThread
    private static ImmutableTriple<ImageResult, List<Image>, Runnable> updateImages(final ILoggingManager loggingManager, final String logId, final List<Image> oldImages, final List<Image> newImages, final Consumer<String> progress) {

        final Map<String, Image> oldImageMap = oldImages.stream()
            .filter(img -> img.serviceImageId != null)
            .collect(Collectors.toMap(img -> img.serviceImageId, img -> img, (i1, i2) -> i1, HashMap::new));

        ImageResult result = ImageResult.ok("");
        final List<Image> adaptedImageList = new ArrayList<>();
        final List<Uri> localImageUrisToDelete = new ArrayList<>();

        int imgPos = 0;
        int imgCount = newImages.size();
        for (Image newImg : newImages) {
            final Image oldImg = oldImageMap.remove(newImg.serviceImageId);
            final String newTitle = getLogImageTitle(newImg, imgPos, imgCount);

            if (newImg.serviceImageId == null || oldImg == null) {
                //New Image -> upload
                progress.accept(LocalizationUtils.getString(R.string.log_posting_image_create, String.valueOf(imgPos + 1), String.valueOf(imgCount)));
                result = uploadNewImage(loggingManager, logId, newImg, imgPos, imgCount);
                adaptedImageList.add(newImg.buildUpon()
                    .setServiceImageId(result.getServiceImageId())
                    .setUrl(result.getImageUri())
                    .setTitle(newTitle)
                    .build());

                if (result.isOk()) {
                    localImageUrisToDelete.add(newImg.getUri());
                }

            } else if (loggingManager.supportsEditLogImages() && !imagePropertiesEqual(oldImg, newImg, newTitle)) {
                //Existing image with changed properties -> edit
                progress.accept(LocalizationUtils.getString(R.string.log_posting_image_edit, String.valueOf(imgPos + 1), String.valueOf(imgCount)));
                result = loggingManager.editLogImage(logId, newImg.serviceImageId, getLogImageTitle(newImg, imgPos, imgCount), newImg.getDescription());
                adaptedImageList.add(newImg.buildUpon()
                    .setTitle(newTitle)
                    .build());
            } else {
                //image unchanged
                adaptedImageList.add(newImg.buildUpon()
                    .setTitle(newTitle)
                    .build());
            }
            if (!result.isOk()) {
                return new ImmutableTriple<>(result, Collections.emptyList(), () -> { });
            }
            imgPos++;
        }

        if (loggingManager.supportsDeleteLogImages()) {
            imgPos = 0;
            imgCount = oldImageMap.size();
            for (String oldImgIdToRemove : oldImageMap.keySet()) {
                progress.accept(LocalizationUtils.getString(R.string.log_posting_image_delete, String.valueOf(imgPos + 1), String.valueOf(imgCount)));
                //remove image from log
                result = loggingManager.deleteLogImage(logId, oldImgIdToRemove);
                if (!result.isOk()) {
                    return new ImmutableTriple<>(result, Collections.emptyList(), () -> { });
                }
            }
        }
        return new ImmutableTriple<>(result, adaptedImageList, () -> {
            for (Uri uri : localImageUrisToDelete) {
                ImageUtils.deleteImage(uri);
            }
        });
    }
get title for a log image in the list
main/src/main/java/cgeo/geocaching/log/LogUtils.java