Last active
June 25, 2019 21:01
-
-
Save jaredrummler/e7e33963a794c02d163d5bf11fabb5ba to your computer and use it in GitHub Desktop.
Setup a FileProvider for Android with paths for root, external storage, and internal app files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<manifest package="com.jaredrummler.android.common" | |
xmlns:android="http://schemas.android.com/apk/res/android"> | |
<application> | |
<provider | |
android:name="com.jaredrummler.android.files.FileProvider" | |
android:authorities="${applicationId}.fileprovider" | |
android:exported="false" | |
android:grantUriPermissions="true"> | |
<meta-data | |
android:name="android.support.FILE_PROVIDER_PATHS" | |
android:resource="@xml/root_paths"/> | |
</provider> | |
</application> | |
</manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.jaredrummler.android.files; | |
import android.database.Cursor; | |
import android.database.MatrixCursor; | |
import android.net.Uri; | |
import android.provider.MediaStore; | |
import java.util.Arrays; | |
/** | |
* A {@link FileProvider} that supports apps which rely on {@link MediaStore.MediaColumns#DATA} | |
* | |
* @see <a href="http://stackoverflow.com/a/25020642">http://stackoverflow.com/a/25020642</a> | |
*/ | |
public class FileProvider extends android.support.v4.content.FileProvider { | |
public static final String AUTHORITY = App.getContext().getPackageName() + ".fileprovider"; | |
@Override | |
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { | |
final Cursor source = super.query(uri, projection, selection, selectionArgs, sortOrder); | |
/* | |
It's not necessary to overwrite | |
public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] | |
selectionArgs, final String sortOrder, final CancellationSignal cancellationSignal); | |
cause it calls this method. | |
== What's happening here? == | |
Some apps rely on the MediaStore.MediaColumns.DATA column in the cursor. To prevent them | |
from crashing, we have to copy the initial cursor and add the MediaStore.MediaColumns.DATA | |
column. The values of this column will always be null, but we assume that they are able | |
to handle that case. | |
*/ | |
if (source == null) { | |
android.util.Log.w("TAG", "Not able to apply workaround, super.query(...) returned null"); | |
return null; | |
} | |
String[] columnNames = source.getColumnNames(); | |
String[] newColumnNames = columnNamesWithData(columnNames); | |
MatrixCursor cursor = new MatrixCursor(newColumnNames, source.getCount()); | |
if (cursor.moveToFirst()) { | |
do { | |
MatrixCursor.RowBuilder row = cursor.newRow(); | |
for (int i = 0; i < columnNames.length; i++) { | |
row.add(source.getString(i)); | |
} | |
} while (cursor.moveToNext()); | |
} | |
source.close(); | |
return cursor; | |
} | |
private String[] columnNamesWithData(String[] columnNames) { | |
for (String columnName : columnNames) { | |
if (MediaStore.MediaColumns.DATA.equals(columnName)) { | |
return columnNames; | |
} | |
} | |
String[] newColumnNames = Arrays.copyOf(columnNames, columnNames.length + 1); | |
newColumnNames[columnNames.length] = MediaStore.MediaColumns.DATA; | |
return newColumnNames; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<paths> | |
<root-path | |
name="root" | |
path="."/> | |
<files-path | |
name="files" | |
path="."/> | |
<cache-path | |
name="cache" | |
path="."/> | |
<external-path | |
name="external" | |
path="."/> | |
<external-files-path | |
name="external-files" | |
path="."/> | |
<external-cache-path | |
name="external-cache" | |
path="."/> | |
</paths> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment