Search in sources :

Example 1 with MediaFile

use of org.odk.collect.android.logic.MediaFile in project collect by opendatakit.

the class DownloadFormListTask method isMediaFileAlreadyDownloaded.

private boolean isMediaFileAlreadyDownloaded(File[] localMediaFiles, MediaFile newMediaFile) {
    // TODO Zip files are ignored we should find a way to take them into account too
    if (newMediaFile.getFilename().endsWith(".zip")) {
        return true;
    }
    String mediaFileHash = newMediaFile.getHash();
    mediaFileHash = mediaFileHash.substring(4, mediaFileHash.length());
    for (File localMediaFile : localMediaFiles) {
        if (mediaFileHash.equals(FileUtils.getMd5Hash(localMediaFile))) {
            return true;
        }
    }
    return false;
}
Also used : File(java.io.File) MediaFile(org.odk.collect.android.logic.MediaFile)

Example 2 with MediaFile

use of org.odk.collect.android.logic.MediaFile in project collect by opendatakit.

the class DownloadFormListTask method downloadMediaFileList.

private List<MediaFile> downloadMediaFileList(String manifestUrl) {
    if (manifestUrl == null) {
        return null;
    }
    // get shared HttpContext so that authentication and cookies are retained.
    HttpContext localContext = Collect.getInstance().getHttpContext();
    HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
    DocumentFetchResult result = WebUtils.getXmlDocument(manifestUrl, localContext, httpclient);
    if (result.errorMessage != null) {
        return null;
    }
    String errMessage = Collect.getInstance().getString(R.string.access_error, manifestUrl);
    if (!result.isOpenRosaResponse) {
        errMessage += Collect.getInstance().getString(R.string.manifest_server_error);
        Timber.e(errMessage);
        return null;
    }
    // Attempt OpenRosa 1.0 parsing
    Element manifestElement = result.doc.getRootElement();
    if (!manifestElement.getName().equals("manifest")) {
        errMessage += Collect.getInstance().getString(R.string.root_element_error, manifestElement.getName());
        Timber.e(errMessage);
        return null;
    }
    String namespace = manifestElement.getNamespace();
    if (!DownloadFormsTask.isXformsManifestNamespacedElement(manifestElement)) {
        errMessage += Collect.getInstance().getString(R.string.root_namespace_error, namespace);
        Timber.e(errMessage);
        return null;
    }
    int elements = manifestElement.getChildCount();
    List<MediaFile> files = new ArrayList<>();
    for (int i = 0; i < elements; ++i) {
        if (manifestElement.getType(i) != Element.ELEMENT) {
            // e.g., whitespace (text)
            continue;
        }
        Element mediaFileElement = manifestElement.getElement(i);
        if (!DownloadFormsTask.isXformsManifestNamespacedElement(mediaFileElement)) {
            // someone else's extension?
            continue;
        }
        String name = mediaFileElement.getName();
        if (name.equalsIgnoreCase("mediaFile")) {
            String filename = null;
            String hash = null;
            String downloadUrl = null;
            // don't process descriptionUrl
            int childCount = mediaFileElement.getChildCount();
            for (int j = 0; j < childCount; ++j) {
                if (mediaFileElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                Element child = mediaFileElement.getElement(j);
                if (!DownloadFormsTask.isXformsManifestNamespacedElement(child)) {
                    // someone else's extension?
                    continue;
                }
                String tag = child.getName();
                switch(tag) {
                    case "filename":
                        filename = XFormParser.getXMLText(child, true);
                        if (filename != null && filename.length() == 0) {
                            filename = null;
                        }
                        break;
                    case "hash":
                        hash = XFormParser.getXMLText(child, true);
                        if (hash != null && hash.length() == 0) {
                            hash = null;
                        }
                        break;
                    case "downloadUrl":
                        downloadUrl = XFormParser.getXMLText(child, true);
                        if (downloadUrl != null && downloadUrl.length() == 0) {
                            downloadUrl = null;
                        }
                        break;
                }
            }
            if (filename == null || downloadUrl == null || hash == null) {
                errMessage += Collect.getInstance().getString(R.string.manifest_tag_error, Integer.toString(i));
                Timber.e(errMessage);
                return null;
            }
            files.add(new MediaFile(filename, hash, downloadUrl));
        }
    }
    return files;
}
Also used : MediaFile(org.odk.collect.android.logic.MediaFile) DocumentFetchResult(org.odk.collect.android.utilities.DocumentFetchResult) HttpClient(org.opendatakit.httpclientandroidlib.client.HttpClient) Element(org.kxml2.kdom.Element) HttpContext(org.opendatakit.httpclientandroidlib.protocol.HttpContext) ArrayList(java.util.ArrayList)

Example 3 with MediaFile

use of org.odk.collect.android.logic.MediaFile in project collect by opendatakit.

the class DownloadFormsTask method downloadManifestAndMediaFiles.

private String downloadManifestAndMediaFiles(String tempMediaPath, String finalMediaPath, FormDetails fd, int count, int total) throws Exception {
    if (fd.getManifestUrl() == null) {
        return null;
    }
    publishProgress(Collect.getInstance().getString(R.string.fetching_manifest, fd.getFormName()), String.valueOf(count), String.valueOf(total));
    List<MediaFile> files = new ArrayList<MediaFile>();
    // get shared HttpContext so that authentication and cookies are retained.
    HttpContext localContext = Collect.getInstance().getHttpContext();
    HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
    DocumentFetchResult result = WebUtils.getXmlDocument(fd.getManifestUrl(), localContext, httpclient);
    if (result.errorMessage != null) {
        return result.errorMessage;
    }
    String errMessage = Collect.getInstance().getString(R.string.access_error, fd.getManifestUrl());
    if (!result.isOpenRosaResponse) {
        errMessage += Collect.getInstance().getString(R.string.manifest_server_error);
        Timber.e(errMessage);
        return errMessage;
    }
    // Attempt OpenRosa 1.0 parsing
    Element manifestElement = result.doc.getRootElement();
    if (!manifestElement.getName().equals("manifest")) {
        errMessage += Collect.getInstance().getString(R.string.root_element_error, manifestElement.getName());
        Timber.e(errMessage);
        return errMessage;
    }
    String namespace = manifestElement.getNamespace();
    if (!isXformsManifestNamespacedElement(manifestElement)) {
        errMessage += Collect.getInstance().getString(R.string.root_namespace_error, namespace);
        Timber.e(errMessage);
        return errMessage;
    }
    int elements = manifestElement.getChildCount();
    for (int i = 0; i < elements; ++i) {
        if (manifestElement.getType(i) != Element.ELEMENT) {
            // e.g., whitespace (text)
            continue;
        }
        Element mediaFileElement = manifestElement.getElement(i);
        if (!isXformsManifestNamespacedElement(mediaFileElement)) {
            // someone else's extension?
            continue;
        }
        String name = mediaFileElement.getName();
        if (name.equalsIgnoreCase("mediaFile")) {
            String filename = null;
            String hash = null;
            String downloadUrl = null;
            // don't process descriptionUrl
            int childCount = mediaFileElement.getChildCount();
            for (int j = 0; j < childCount; ++j) {
                if (mediaFileElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                Element child = mediaFileElement.getElement(j);
                if (!isXformsManifestNamespacedElement(child)) {
                    // someone else's extension?
                    continue;
                }
                String tag = child.getName();
                switch(tag) {
                    case "filename":
                        filename = XFormParser.getXMLText(child, true);
                        if (filename != null && filename.length() == 0) {
                            filename = null;
                        }
                        break;
                    case "hash":
                        hash = XFormParser.getXMLText(child, true);
                        if (hash != null && hash.length() == 0) {
                            hash = null;
                        }
                        break;
                    case "downloadUrl":
                        downloadUrl = XFormParser.getXMLText(child, true);
                        if (downloadUrl != null && downloadUrl.length() == 0) {
                            downloadUrl = null;
                        }
                        break;
                }
            }
            if (filename == null || downloadUrl == null || hash == null) {
                errMessage += Collect.getInstance().getString(R.string.manifest_tag_error, Integer.toString(i));
                Timber.e(errMessage);
                return errMessage;
            }
            files.add(new MediaFile(filename, hash, downloadUrl));
        }
    }
    // OK we now have the full set of files to download...
    Timber.i("Downloading %d media files.", files.size());
    int mediaCount = 0;
    if (files.size() > 0) {
        File tempMediaDir = new File(tempMediaPath);
        File finalMediaDir = new File(finalMediaPath);
        FileUtils.checkMediaPath(tempMediaDir);
        FileUtils.checkMediaPath(finalMediaDir);
        for (MediaFile toDownload : files) {
            ++mediaCount;
            publishProgress(Collect.getInstance().getString(R.string.form_download_progress, fd.getFormName(), String.valueOf(mediaCount), String.valueOf(files.size())), String.valueOf(count), String.valueOf(total));
            // try {
            File finalMediaFile = new File(finalMediaDir, toDownload.getFilename());
            File tempMediaFile = new File(tempMediaDir, toDownload.getFilename());
            if (!finalMediaFile.exists()) {
                downloadFile(tempMediaFile, toDownload.getDownloadUrl());
            } else {
                String currentFileHash = FileUtils.getMd5Hash(finalMediaFile);
                String downloadFileHash = getMd5Hash(toDownload.getHash());
                if (currentFileHash != null && downloadFileHash != null && !currentFileHash.contentEquals(downloadFileHash)) {
                    // if the hashes match, it's the same file
                    // otherwise delete our current one and replace it with the new one
                    FileUtils.deleteAndReport(finalMediaFile);
                    downloadFile(tempMediaFile, toDownload.getDownloadUrl());
                } else {
                    // exists, and the hash is the same
                    // no need to download it again
                    Timber.i("Skipping media file fetch -- file hashes identical: %s", finalMediaFile.getAbsolutePath());
                }
            }
        // } catch (Exception e) {
        // return e.getLocalizedMessage();
        // }
        }
    }
    return null;
}
Also used : MediaFile(org.odk.collect.android.logic.MediaFile) DocumentFetchResult(org.odk.collect.android.utilities.DocumentFetchResult) HttpClient(org.opendatakit.httpclientandroidlib.client.HttpClient) Element(org.kxml2.kdom.Element) ArrayList(java.util.ArrayList) HttpContext(org.opendatakit.httpclientandroidlib.protocol.HttpContext) MediaFile(org.odk.collect.android.logic.MediaFile) File(java.io.File)

Example 4 with MediaFile

use of org.odk.collect.android.logic.MediaFile in project collect by opendatakit.

the class DownloadFormListTask method doInBackground.

@Override
protected HashMap<String, FormDetails> doInBackground(Void... values) {
    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(Collect.getInstance().getBaseContext());
    String downloadListUrl = settings.getString(PreferenceKeys.KEY_SERVER_URL, Collect.getInstance().getString(R.string.default_server_url));
    // NOTE: /formlist must not be translated! It is the well-known path on the server.
    String formListUrl = Collect.getInstance().getApplicationContext().getString(R.string.default_odk_formlist);
    String downloadPath = settings.getString(PreferenceKeys.KEY_FORMLIST_URL, formListUrl);
    downloadListUrl += downloadPath;
    Collect.getInstance().getActivityLogger().logAction(this, formListUrl, downloadListUrl);
    // We populate this with available forms from the specified server.
    // <formname, details>
    HashMap<String, FormDetails> formList = new HashMap<String, FormDetails>();
    // get shared HttpContext so that authentication and cookies are retained.
    HttpContext localContext = Collect.getInstance().getHttpContext();
    HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
    DocumentFetchResult result = WebUtils.getXmlDocument(downloadListUrl, localContext, httpclient);
    // If we can't get the document, return the error, cancel the task
    if (result.errorMessage != null) {
        if (result.responseCode == 401) {
            formList.put(DL_AUTH_REQUIRED, new FormDetails(result.errorMessage));
        } else {
            formList.put(DL_ERROR_MSG, new FormDetails(result.errorMessage));
        }
        return formList;
    }
    if (result.isOpenRosaResponse) {
        // Attempt OpenRosa 1.0 parsing
        Element xformsElement = result.doc.getRootElement();
        if (!xformsElement.getName().equals("xforms")) {
            String error = "root element is not <xforms> : " + xformsElement.getName();
            Timber.e("Parsing OpenRosa reply -- %s", error);
            formList.put(DL_ERROR_MSG, new FormDetails(Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
            return formList;
        }
        String namespace = xformsElement.getNamespace();
        if (!isXformsListNamespacedElement(xformsElement)) {
            String error = "root element namespace is incorrect:" + namespace;
            Timber.e("Parsing OpenRosa reply -- %s", error);
            formList.put(DL_ERROR_MSG, new FormDetails(Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
            return formList;
        }
        int elements = xformsElement.getChildCount();
        for (int i = 0; i < elements; ++i) {
            if (xformsElement.getType(i) != Element.ELEMENT) {
                // e.g., whitespace (text)
                continue;
            }
            Element xformElement = xformsElement.getElement(i);
            if (!isXformsListNamespacedElement(xformElement)) {
                // someone else's extension?
                continue;
            }
            String name = xformElement.getName();
            if (!name.equalsIgnoreCase("xform")) {
                // someone else's extension?
                continue;
            }
            // this is something we know how to interpret
            String formId = null;
            String formName = null;
            String version = null;
            String majorMinorVersion = null;
            String description = null;
            String downloadUrl = null;
            String manifestUrl = null;
            String hash = null;
            // don't process descriptionUrl
            int fieldCount = xformElement.getChildCount();
            for (int j = 0; j < fieldCount; ++j) {
                if (xformElement.getType(j) != Element.ELEMENT) {
                    // whitespace
                    continue;
                }
                Element child = xformElement.getElement(j);
                if (!isXformsListNamespacedElement(child)) {
                    // someone else's extension?
                    continue;
                }
                String tag = child.getName();
                switch(tag) {
                    case "formID":
                        formId = XFormParser.getXMLText(child, true);
                        if (formId != null && formId.length() == 0) {
                            formId = null;
                        }
                        break;
                    case "name":
                        formName = XFormParser.getXMLText(child, true);
                        if (formName != null && formName.length() == 0) {
                            formName = null;
                        }
                        break;
                    case "version":
                        version = XFormParser.getXMLText(child, true);
                        if (version != null && version.length() == 0) {
                            version = null;
                        }
                        break;
                    case "majorMinorVersion":
                        majorMinorVersion = XFormParser.getXMLText(child, true);
                        if (majorMinorVersion != null && majorMinorVersion.length() == 0) {
                            majorMinorVersion = null;
                        }
                        break;
                    case "descriptionText":
                        description = XFormParser.getXMLText(child, true);
                        if (description != null && description.length() == 0) {
                            description = null;
                        }
                        break;
                    case "downloadUrl":
                        downloadUrl = XFormParser.getXMLText(child, true);
                        if (downloadUrl != null && downloadUrl.length() == 0) {
                            downloadUrl = null;
                        }
                        break;
                    case "manifestUrl":
                        manifestUrl = XFormParser.getXMLText(child, true);
                        if (manifestUrl != null && manifestUrl.length() == 0) {
                            manifestUrl = null;
                        }
                        break;
                    case "hash":
                        hash = XFormParser.getXMLText(child, true);
                        if (hash != null && hash.length() == 0) {
                            hash = null;
                        }
                        break;
                }
            }
            if (formId == null || downloadUrl == null || formName == null) {
                String error = "Forms list entry " + Integer.toString(i) + " has missing or empty tags: formID, name, or downloadUrl";
                Timber.e("Parsing OpenRosa reply -- %s", error);
                formList.clear();
                formList.put(DL_ERROR_MSG, new FormDetails(Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
                return formList;
            }
            boolean isNewerFormVersionAvailable = false;
            boolean areNewerMediaFilesAvailable = false;
            if (isThisFormAlreadyDownloaded(formId)) {
                isNewerFormVersionAvailable = isNewerFormVersionAvailable(DownloadFormsTask.getMd5Hash(hash));
                if (!isNewerFormVersionAvailable && manifestUrl != null) {
                    List<MediaFile> newMediaFiles = downloadMediaFileList(manifestUrl);
                    if (newMediaFiles != null && newMediaFiles.size() > 0) {
                        areNewerMediaFilesAvailable = areNewerMediaFilesAvailable(formId, version, newMediaFiles);
                    }
                }
            }
            formList.put(formId, new FormDetails(formName, downloadUrl, manifestUrl, formId, (version != null) ? version : majorMinorVersion, isNewerFormVersionAvailable, areNewerMediaFilesAvailable));
        }
    } else {
        // Aggregate 0.9.x mode...
        // populate HashMap with form names and urls
        Element formsElement = result.doc.getRootElement();
        int formsCount = formsElement.getChildCount();
        String formId = null;
        for (int i = 0; i < formsCount; ++i) {
            if (formsElement.getType(i) != Element.ELEMENT) {
                // whitespace
                continue;
            }
            Element child = formsElement.getElement(i);
            String tag = child.getName();
            if (tag.equals("formID")) {
                formId = XFormParser.getXMLText(child, true);
                if (formId != null && formId.length() == 0) {
                    formId = null;
                }
            }
            if (tag.equalsIgnoreCase("form")) {
                String formName = XFormParser.getXMLText(child, true);
                if (formName != null && formName.length() == 0) {
                    formName = null;
                }
                String downloadUrl = child.getAttributeValue(null, "url");
                downloadUrl = downloadUrl.trim();
                if (downloadUrl != null && downloadUrl.length() == 0) {
                    downloadUrl = null;
                }
                if (downloadUrl == null || formName == null) {
                    String error = "Forms list entry " + Integer.toString(i) + " is missing form name or url attribute";
                    Timber.e("Parsing OpenRosa reply -- %s", error);
                    formList.clear();
                    formList.put(DL_ERROR_MSG, new FormDetails(Collect.getInstance().getString(R.string.parse_legacy_formlist_failed, error)));
                    return formList;
                }
                formList.put(formName, new FormDetails(formName, downloadUrl, null, formId, null, false, false));
                formId = null;
            }
        }
    }
    return formList;
}
Also used : MediaFile(org.odk.collect.android.logic.MediaFile) SharedPreferences(android.content.SharedPreferences) HashMap(java.util.HashMap) Element(org.kxml2.kdom.Element) HttpContext(org.opendatakit.httpclientandroidlib.protocol.HttpContext) FormDetails(org.odk.collect.android.logic.FormDetails) DocumentFetchResult(org.odk.collect.android.utilities.DocumentFetchResult) HttpClient(org.opendatakit.httpclientandroidlib.client.HttpClient)

Aggregations

MediaFile (org.odk.collect.android.logic.MediaFile)4 Element (org.kxml2.kdom.Element)3 DocumentFetchResult (org.odk.collect.android.utilities.DocumentFetchResult)3 HttpClient (org.opendatakit.httpclientandroidlib.client.HttpClient)3 HttpContext (org.opendatakit.httpclientandroidlib.protocol.HttpContext)3 File (java.io.File)2 ArrayList (java.util.ArrayList)2 SharedPreferences (android.content.SharedPreferences)1 HashMap (java.util.HashMap)1 FormDetails (org.odk.collect.android.logic.FormDetails)1