All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.oscim.android.theme.ContentResolverResourceProvider Maven / Gradle / Ivy

Go to download

OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.

There is a newer version: 0.9.2
Show newest version
/*
 * Copyright 2021 eddiemuc
 *
 * This program is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program. If not, see .
 */
package org.oscim.android.theme;

import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import org.oscim.backend.CanvasAdapter;
import org.oscim.theme.XmlThemeResourceProvider;
import org.oscim.utils.IOUtils;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.*;

/**
 * An xml theme resource provider resolving resources using Android scoped storage (document framework).
 * 

* Implementation note: these methods do not use DocumentFile internally, * but query directly for document info due to vastly better performance. * Also for better performance, this implementation caches resource uris. *

* Note: this implementation requires minimum Android 5.0 (API 21) */ public class ContentResolverResourceProvider implements XmlThemeResourceProvider { private final ContentResolver contentResolver; private final Uri relativeRootUri; private final boolean isDocumentUri; private final Map resourceUriCache = new HashMap<>(); private static class DocumentInfo { private final String name; private final Uri uri; private final boolean isDirectory; private DocumentInfo(String name, Uri uri, boolean isDirectory) { this.name = name; this.uri = uri; this.isDirectory = isDirectory; } } /** * Creates a new content resolver resource provider. * * @param contentResolver content resolver used to read content. * @param relativeRootUri uri pointing to a directory. * Uri is assumed to be a pure tree Uri (as e.g. returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}). */ public ContentResolverResourceProvider(ContentResolver contentResolver, Uri relativeRootUri) { this(contentResolver, relativeRootUri, false); } /** * Creates a new content resolver resource provider. * * @param contentResolver content resolver used to read content. * @param relativeRootUri uri pointing to a directory. * @param isDocumentUri Uris as returned e.g. by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}) cannot directly be used to scan directories and read content. * They must be converted to document uris first using {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)}. * However, in some situations this conversion was done previously by caller (e.g. if root dir should be subdirectory of a directory returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}). * In these cases, converted Uri will point to original root directory which is not always the wanted behaviour. * Thus, this parameter allows caller to control whether conversion should be done or not. * If set to true, then given Uri is considered to be a document uri already and no conversion is done. * If set to false, uri is considered to be a pure tree uri as returned e.g. by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}) and it is converted. */ public ContentResolverResourceProvider(ContentResolver contentResolver, Uri relativeRootUri, boolean isDocumentUri) { this.contentResolver = contentResolver; this.relativeRootUri = relativeRootUri; this.isDocumentUri = isDocumentUri; refreshCache(); } /** * Build uri cache for one dir level (recursive function). */ private void buildCacheLevel(String prefix, Uri dirUri) { List docs = queryDir(dirUri); for (DocumentInfo doc : docs) { if (doc.isDirectory) { buildCacheLevel(prefix + doc.name + "/", doc.uri); } else { // Store both relative urls and absolute urls resourceUriCache.put(CanvasAdapter.PREFIX_FILE + prefix + doc.name, doc.uri); resourceUriCache.put(CanvasAdapter.PREFIX_FILE + "/" + prefix + doc.name, doc.uri); } } } @Override public InputStream createInputStream(String relativePath, String source) throws FileNotFoundException { Uri docUri = resourceUriCache.get(source); if (docUri != null) { return contentResolver.openInputStream(docUri); } return null; } /** * Query the content of a directory using scoped storage. * * @return a list of arrays with info [0: name (String), 1: uri (Uri), 2: isDir (boolean)] */ private List queryDir(Uri dirUri) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return Collections.emptyList(); } if (dirUri == null) { return Collections.emptyList(); } List result = new ArrayList<>(); Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(dirUri, DocumentsContract.getDocumentId(dirUri)); String[] columns = new String[]{ DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE }; Cursor c = null; try { c = contentResolver.query(childrenUri, columns, null, null, null); while (c.moveToNext()) { String documentId = c.getString(0); String name = c.getString(1); String mimeType = c.getString(2); Uri uri = DocumentsContract.buildDocumentUriUsingTree(dirUri, documentId); boolean isDir = DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType); result.add(new DocumentInfo(name, uri, isDir)); } return result; } finally { IOUtils.closeQuietly(c); } } /** * Refresh the uri cache by recreating it. */ private void refreshCache() { resourceUriCache.clear(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return; } if (relativeRootUri == null) { return; } Uri dirUri = relativeRootUri; if (!isDocumentUri) { // Convert "tree uri" to a "document uri" dirUri = DocumentsContract.buildDocumentUriUsingTree(dirUri, DocumentsContract.getTreeDocumentId(dirUri)); } buildCacheLevel("", dirUri); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy