keepass2android/src/java/android-filechooser-AS/app/src/main/java/group/pals/android/lib/ui/filechooser/providers/BaseFileProviderUtils.java

657 lines
21 KiB
Java

/*
* Copyright (c) 2012 Hai Bison
*
* See the file LICENSE at the root directory of this project for copying
* permission.
*/
package group.pals.android.lib.ui.filechooser.providers;
import group.pals.android.lib.ui.filechooser.providers.basefile.BaseFileContract.BaseFile;
import group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider;
import group.pals.android.lib.ui.filechooser.utils.ui.Ui;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Bundle;
/**
* Utilities for base file provider.
*
* @author Hai Bison
* @since v5.1 beta
*/
public class BaseFileProviderUtils {
@SuppressWarnings("unused")
private static final String CLASSNAME = BaseFileProviderUtils.class
.getName();
/**
* Map of provider ID to its authority.
* <p/>
* <b>Note for developers:</b> If you provide your own provider, use
* {@link #registerProviderInfo(String, String)} to register it..
*/
private static final Map<String, Bundle> MAP_PROVIDER_INFO = new HashMap<String, Bundle>();
private static final String COLUMN_AUTHORITY = "authority";
/**
* Registers a file provider.
*
* @param id
* the provider ID. It should be a UUID.
* @param authority
* the autority.
*/
public static void registerProviderInfo(String id, String authority) {
Bundle bundle = new Bundle();
bundle.putString(COLUMN_AUTHORITY, authority);
MAP_PROVIDER_INFO.put(id, bundle);
}// registerProviderInfo()
/**
* Gets provider authority from its ID.
*
* @param providerId
* the provider ID.
* @return the provider authority, or {@code null} if not available.
*/
public static String getProviderAuthority(String providerId) {
return MAP_PROVIDER_INFO.get(providerId).getString(COLUMN_AUTHORITY);
}// getProviderAuthority()
/**
* Gets provider ID from its authority.
*
* @param authority
* the provider authority.
* @return the provider ID, or {@code null} if not available.
*/
public static String getProviderId(String authority) {
for (Entry<String, Bundle> entry : MAP_PROVIDER_INFO.entrySet())
if (entry.getValue().getString(COLUMN_AUTHORITY).equals(authority))
return entry.getKey();
return null;
}// getProviderId()
/**
* Gets provider name from its ID.
* <p/>
* <b>Note:</b> You should always use the method
* {@link #getProviderName(Context, String)} rather than this one whenever
* possible. Because this method does not guarantee the result.
*
* @param providerId
* the provider ID.
* @return the provider name, or {@code null} if not available.
*/
private static String getProviderName(String providerId) {
return MAP_PROVIDER_INFO.get(providerId).getString(
BaseFile.COLUMN_PROVIDER_NAME);
}// getProviderName()
/**
* Gets provider name from its ID.
*
* @param context
* {@link Context}.
* @param providerId
* the provider ID.
* @return the provider name, can be {@code null} if not provided.
*/
public static String getProviderName(Context context, String providerId) {
if (getProviderAuthority(providerId) == null)
return null;
String result = getProviderName(providerId);
if (result == null) {
Cursor cursor = context
.getContentResolver()
.query(BaseFile
.genContentUriApi(getProviderAuthority(providerId)),
null, null, null, null);
if (cursor == null)
return null;
try {
if (cursor.moveToFirst()) {
result = cursor.getString(cursor
.getColumnIndex(BaseFile.COLUMN_PROVIDER_NAME));
setProviderName(providerId, result);
} else
return null;
} finally {
cursor.close();
}
}
return result;
}// getProviderName()
/**
* Sets provider name.
*
* @param providerId
* the provider ID.
* @param providerName
* the provider name.
*/
private static void setProviderName(String providerId, String providerName) {
MAP_PROVIDER_INFO.get(providerId).putString(
BaseFile.COLUMN_PROVIDER_NAME, providerName);
}// setProviderName()
/**
* Gets the provider icon (badge) resource ID.
*
* @param context
* the context. The resource ID will be retrieved based on this
* context's theme (for example light or dark).
* @param providerId
* the provider ID.
* @return the resource ID of the icon (badge).
*/
public static int getProviderIconId(Context context, String providerId) {
int attr = MAP_PROVIDER_INFO.get(providerId).getInt(
BaseFile.COLUMN_PROVIDER_ICON_ATTR);
if (attr == 0) {
Cursor cursor = context
.getContentResolver()
.query(BaseFile
.genContentUriApi(getProviderAuthority(providerId)),
null, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
attr = cursor
.getInt(cursor
.getColumnIndex(BaseFile.COLUMN_PROVIDER_ICON_ATTR));
MAP_PROVIDER_INFO.get(providerId).putInt(
BaseFile.COLUMN_PROVIDER_ICON_ATTR, attr);
}
} finally {
cursor.close();
}
}
}
int res = Ui.resolveAttribute(context, attr);
if (res == 0)
res = attr;
return res;
}// getProviderIconId()
/**
* Default columns of a base file cursor.
* <p/>
* The column orders are:
* <p/>
* <ol>
* <li>{@link BaseFile#_ID}</li>
* <li>{@link BaseFile#COLUMN_URI}</li>
* <li>{@link BaseFile#COLUMN_REAL_URI}</li>
* <li>{@link BaseFile#COLUMN_NAME}</li>
* <li>{@link BaseFile#COLUMN_CAN_READ}</li>
* <li>{@link BaseFile#COLUMN_CAN_WRITE}</li>
* <li>{@link BaseFile#COLUMN_SIZE}</li>
* <li>{@link BaseFile#COLUMN_TYPE}</li>
* <li>{@link BaseFile#COLUMN_MODIFICATION_TIME}</li>
* <li>{@link BaseFile#COLUMN_ICON_ID}</li>
* </ol>
*/
public static final String[] BASE_FILE_CURSOR_COLUMNS = { BaseFile._ID,
BaseFile.COLUMN_URI, BaseFile.COLUMN_REAL_URI,
BaseFile.COLUMN_NAME, BaseFile.COLUMN_CAN_READ,
BaseFile.COLUMN_CAN_WRITE, BaseFile.COLUMN_SIZE,
BaseFile.COLUMN_TYPE, BaseFile.COLUMN_MODIFICATION_TIME,
BaseFile.COLUMN_ICON_ID };
public static final String[] CONNECTION_CHECK_CURSOR_COLUMNS = {"error"};
/**
* Creates new cursor which holds default properties of a base file for
* client to access.
*
* @return the new empty cursor. The columns are
* {@link #BASE_FILE_CURSOR_COLUMNS}.
*/
public static MatrixCursor newBaseFileCursor() {
return new MatrixCursor(BASE_FILE_CURSOR_COLUMNS);
}// newBaseFileCursor()
/**
* Creates new cursor, closes it and returns it ^^
*
* @return the newly closed cursor.
*/
public static MatrixCursor newClosedCursor() {
MatrixCursor cursor = new MatrixCursor(new String[0]);
cursor.close();
return cursor;
}// newClosedCursor()
/**
* Checks if {@code uri} is a directory.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to check.
* @return {@code true} if {@code uri} is a directory, {@code false}
* otherwise.
*/
public static boolean isDirectory(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return false;
try {
if (cursor.moveToFirst())
return isDirectory(cursor);
return false;
} finally {
cursor.close();
}
}// isDirectory()
/**
* Checks if {@code cursor} is a directory.
*
* @param cursor
* the cursor points to a file.
* @return {@code true} if {@code cursor} is a directory, {@code false}
* otherwise.
*/
public static boolean isDirectory(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_TYPE)) == BaseFile.FILE_TYPE_DIRECTORY;
}// isDirectory()
/**
* Checks if {@code uri} is a file.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to check.
* @return {@code true} if {@code uri} is a file, {@code false} otherwise.
*/
public static boolean isFile(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return false;
try {
if (cursor.moveToFirst())
return isFile(cursor);
return false;
} finally {
cursor.close();
}
}// isFile()
/**
* Checks if {@code cursor} is a file.
*
* @param cursor
* the cursor points to a file.
* @return {@code true} if {@code uri} is a file, {@code false} otherwise.
*/
public static boolean isFile(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_TYPE)) == BaseFile.FILE_TYPE_FILE;
}// isFile()
/**
* Gets file name of {@code uri}.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to get.
* @return the file name if {@code uri} is a file, {@code null} otherwise.
*/
public static String getFileName(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return null;
try {
if (cursor.moveToFirst())
return getFileName(cursor);
return null;
} finally {
cursor.close();
}
}// getFileName()
/**
* Gets filename of {@code cursor}.
*
* @param cursor
* the cursor points to a file.
* @return the filename.
*/
public static String getFileName(Cursor cursor) {
return cursor.getString(cursor.getColumnIndex(BaseFile.COLUMN_NAME));
}// getFileName()
/**
* Gets the real URI of {@code uri}. This is independent of the content
* provider's URI ({@code uri}). For example with {@link LocalFileProvider},
* this method gets the URI which you can create new {@link File} object
* directly from it.
*
* @param context
* {@link Context}.
* @param uri
* the content provider URI which you want to get real URI from.
* @return the real URI of {@code uri}.
*/
public static Uri getRealUri(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return null;
try {
if (cursor.moveToFirst())
return getRealUri(cursor);
return null;
} finally {
cursor.close();
}
}// getRealUri()
/**
* Gets the real URI. This is independent of the content provider's URI
* which {@code cursor} points to. For example with
* {@link LocalFileProvider}, this method gets the URI which you can create
* new {@link File} object directly from it.
*
* @param cursor
* the cursor points to a file.
* @return the real URI.
*/
public static Uri getRealUri(Cursor cursor) {
return Uri.parse(cursor.getString(cursor
.getColumnIndex(BaseFile.COLUMN_REAL_URI)));
}// getRealUri()
/**
* Gets file type of the file pointed by {@code uri}.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to get.
* @return the file type of {@code uri}, can be one of
* {@link #FILE_TYPE_DIRECTORY}, {@link #FILE_TYPE_FILE},
* {@link #FILE_TYPE_UNKNOWN}, {@link #FILE_TYPE_NOT_EXISTED}.
*/
public static int getFileType(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return BaseFile.FILE_TYPE_NOT_EXISTED;
try {
if (cursor.moveToFirst())
return getFileType(cursor);
return BaseFile.FILE_TYPE_NOT_EXISTED;
} finally {
cursor.close();
}
}// getFileType()
/**
* Gets file type of the file pointed by {@code cursor}.
*
* @param cursor
* the cursor points to a file.
* @return the file type, can be one of {@link #FILE_TYPE_DIRECTORY},
* {@link #FILE_TYPE_FILE}, {@link #FILE_TYPE_UNKNOWN},
* {@link #FILE_TYPE_NOT_EXISTED}.
*/
public static int getFileType(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_TYPE));
}// getFileType()
/**
* Gets URI of {@code cursor}.
*
* @param cursor
* the cursor points to a file.
* @return the URI.
*/
public static Uri getUri(Cursor cursor) {
return Uri.parse(cursor.getString(cursor
.getColumnIndex(BaseFile.COLUMN_URI)));
}// getFileName()
/**
* Checks if the file pointed by {@code uri} is existed or not.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to check.
* @return {@code true} or {@code false}.
*/
public static boolean fileExists(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return false;
try {
if (cursor.moveToFirst())
return cursor.getInt(cursor
.getColumnIndex(BaseFile.COLUMN_TYPE)) != BaseFile.FILE_TYPE_NOT_EXISTED;
return false;
} finally {
cursor.close();
}
}// fileExists()
/**
* Checks if the file pointed by {@code uri} is readable or not.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to check.
* @return {@code true} or {@code false}.
*/
public static boolean fileCanRead(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return false;
try {
if (cursor.moveToFirst())
return fileCanRead(cursor);
return false;
} finally {
cursor.close();
}
}// fileCanRead()
/**
* Checks if the file pointed be {@code cursor} is readable or not.
*
* @param cursor
* the cursor points to a file.
* @return {@code true} or {@code false}.
*/
public static boolean fileCanRead(Cursor cursor) {
if (cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_CAN_READ)) != 0) {
switch (cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_TYPE))) {
case BaseFile.FILE_TYPE_DIRECTORY:
case BaseFile.FILE_TYPE_FILE:
return true;
}
}
return false;
}// fileCanRead()
/**
* Checks if the file pointed by {@code uri} is writable or not.
*
* @param context
* {@link Context}.
* @param uri
* the URI you want to check.
* @return {@code true} or {@code false}.
*/
public static boolean fileCanWrite(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null,
null, null);
if (cursor == null)
return false;
try {
if (cursor.moveToFirst())
return fileCanWrite(cursor);
return false;
} finally {
cursor.close();
}
}// fileCanWrite()
/**
* Checks if the file pointed by {@code cursor} is writable or not.
*
* @param cursor
* the cursor points to a file.
* @return {@code true} or {@code false}.
*/
public static boolean fileCanWrite(Cursor cursor) {
if (cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_CAN_WRITE)) != 0) {
switch (cursor.getInt(cursor.getColumnIndex(BaseFile.COLUMN_TYPE))) {
case BaseFile.FILE_TYPE_DIRECTORY:
case BaseFile.FILE_TYPE_FILE:
return true;
}
}
return false;
}// fileCanWrite()
/**
* Gets default path of a provider.
*
* @param context
* {@link Context}.
* @param authority
* the provider's authority.
* @return the default path, can be {@code null}.
*/
public static Uri getDefaultPath(Context context, String authority) {
Cursor cursor = context.getContentResolver().query(
BaseFile.genContentUriApi(authority).buildUpon()
.appendPath(BaseFile.CMD_GET_DEFAULT_PATH).build(),
null, null, null, null);
if (cursor == null)
return null;
try {
if (cursor.moveToFirst())
return Uri.parse(cursor.getString(cursor
.getColumnIndex(BaseFile.COLUMN_URI)));
return null;
} finally {
cursor.close();
}
}// getDefaultPath()
/**
* Gets parent directory of {@code uri}.
*
* @param context
* {@link Context}.
* @param uri
* the URI of an existing file.
* @return the parent file if it exists, {@code null} otherwise.
*/
public static Uri getParentFile(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(
BaseFile.genContentUriApi(uri.getAuthority())
.buildUpon()
.appendPath(BaseFile.CMD_GET_PARENT)
.appendQueryParameter(BaseFile.PARAM_SOURCE,
uri.getLastPathSegment()).build(), null, null,
null, null);
if (cursor == null)
return null;
try {
if (cursor.moveToFirst())
return Uri.parse(cursor.getString(cursor
.getColumnIndex(BaseFile.COLUMN_URI)));
return null;
} finally {
cursor.close();
}
}// getParentFile()
/**
* Checks if {@code uri1} is ancestor of {@code uri2}.
*
* @param context
* {@link Context}.
* @param uri1
* the first URI.
* @param uri2
* the second URI.
* @return {@code true} if {@code uri1} is ancestor of {@code uri2},
* {@code false} otherwise.
*/
public static boolean isAncestorOf(Context context, Uri uri1, Uri uri2) {
return context.getContentResolver().query(
BaseFile.genContentUriApi(uri1.getAuthority())
.buildUpon()
.appendPath(BaseFile.CMD_IS_ANCESTOR_OF)
.appendQueryParameter(BaseFile.PARAM_SOURCE,
uri1.getLastPathSegment())
.appendQueryParameter(BaseFile.PARAM_TARGET,
uri2.getLastPathSegment()).build(), null, null,
null, null) != null;
}// isAncestorOf()
/**
* Cancels a task with its ID.
*
* @param context
* the context.
* @param authority
* the file provider authority.
* @param taskId
* the task ID.
*/
public static void cancelTask(Context context, String authority, int taskId) {
context.getContentResolver().query(
BaseFile.genContentUriApi(authority)
.buildUpon()
.appendPath(BaseFile.CMD_CANCEL)
.appendQueryParameter(BaseFile.PARAM_TASK_ID,
Integer.toString(taskId)).build(), null, null,
null, null);
}// cancelTask()
}