package org.julianfamily.keepassgo; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.OpenableColumns; import java.io.File; import java.io.FileNotFoundException; public final class SharedVaultProvider extends ContentProvider { private static final String AUTHORITY = "org.julianfamily.keepassgo.share"; @Override public boolean onCreate() { return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { File file = resolveSharedFile(uri); String[] columns = projection; if (columns == null || columns.length == 0) { columns = new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}; } MatrixCursor cursor = new MatrixCursor(columns, 1); Object[] row = new Object[columns.length]; for (int i = 0; i < columns.length; i++) { switch (columns[i]) { case OpenableColumns.DISPLAY_NAME: row[i] = file.getName(); break; case OpenableColumns.SIZE: row[i] = file.length(); break; default: row[i] = null; break; } } cursor.addRow(row); return cursor; } @Override public String getType(Uri uri) { return "application/x-keepass2"; } @Override public Uri insert(Uri uri, ContentValues values) { throw new UnsupportedOperationException("insert is not supported"); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("delete is not supported"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("update is not supported"); } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File file = resolveSharedFile(uri); return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } static Uri uriForFile(String name) { return new Uri.Builder() .scheme("content") .authority(AUTHORITY) .appendPath(name) .build(); } private File resolveSharedFile(Uri uri) { if (getContext() == null) { throw new IllegalStateException("provider context is unavailable"); } String name = sanitizeFilename(uri.getLastPathSegment()); return new File(AndroidShare.sharedDirectory(getContext()), name); } private static String sanitizeFilename(String name) { if (name == null) { return "shared-vault.kdbx"; } String trimmed = name.trim(); if (trimmed.isEmpty()) { return "shared-vault.kdbx"; } return new File(trimmed).getName(); } }