This is the way i used finally, hope this will help someone.
Added provider in manifest file
<provider
android:name=".AssetsProvider"
android:authorities="yourpackage.provider"
android:exported="true"
android:grantUriPermissions="true"
android:readPermission="yourpermission"></provider>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
</activity>
Following inProvider Activity onCreate() to get assets list and return uriArray to caller (Consumer App)
String[] assetFilesList = null;
// Get Asset Mangaer
AssetManager assetManager = getAssets();
try {
assetFilesList = assetManager.list();
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
// Set up an Intent to send back to apps that request files
mResultIntent = new Intent("yourpackage.ACTION_SEND_MULTIPLE");
// new Uri list
ArrayList<Uri> uriArrayList = new ArrayList<>();
// Set the Activity's result to null to begin with
setResult(Activity.RESULT_CANCELED, null);
Uri fileUri;
if (assetFilesList != null) {
for (String currFile : assetFilesList) {
Log.i(TAG, "Adding File " + currFile);
// parse and create uri
fileUri = Uri.parse("content://" + this.getPackageName() + ".provider/" + currFile);
// add current file uri to the list
uriArrayList.add(fileUri);
}
}
else {
Log.e(TAG, "files array is pointing to null");
}
if (uriArrayList.size() != 0) {
// Put the UriList Intent
mResultIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriArrayList);
mResultIntent.setType("application/octet-stream");
// Set the result
this.setResult(Activity.RESULT_OK, mResultIntent);
} else {
// Set the result to failed
mResultIntent.setDataAndType(null, "");
this.setResult(RESULT_CANCELED, mResultIntent);
}
// Finish Activity and return Result to Caller
finish();
My Assets Provider Class, I have not implemented query, update etc... as these are not necessary for my case.
public class AssetsProvider extends ContentProvider {
static final String TAG = "AssetsProvider";
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
Log.v(TAG, "AssetsGetter: Open asset file " + uri.toString());
AssetManager am = getContext().getAssets();
String file_name = uri.getLastPathSegment();
if (file_name == null)
throw new FileNotFoundException();
AssetFileDescriptor afd = null;
try {
afd = am.openFd(file_name);
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
return afd;
}
@Override
public String getType(Uri p1) {
// TODO: Implement this method
return null;
}
@Override
public int delete(Uri p1, String p2, String[] p3) {
// TODO: Implement this method
return 0;
}
@Override
public Cursor query(Uri p1, String[] p2, String p3, String[] p4, String p5) {
// TODO: Implement this method
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
// TODO: Implement this method
return super.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
}
@Override
public Uri insert(Uri p1, ContentValues p2) {
// TODO: Implement this method
return null;
}
@Override
public boolean onCreate() {
// TODO: Implement this method
return false;
}
@Override
public int update(Uri p1, ContentValues p2, String p3, String[] p4) {
// TODO: Implement this method
return 0;
}
}
Gradle build options to avoid compression for assets files (these are the types of files i had in assets)
aaptOptions {
noCompress '.json' , '.xls'
}
Following in the Consumer activity
In onCreate() -- setPackage() is required since we want send ACTION_PICK to specific application
Intent mRequestFileIntent = new Intent(Intent.ACTION_PICK);
mRequestFileIntent.setPackage("yourAssetsProviderpackage");
mRequestFileIntent.setType("application/octet-stream");
try {
startActivityForResult(mRequestFileIntent, 0);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Install Assets Provider app before start", Toast.LENGTH_LONG).show();
finish();
}
Added Override method onActivityResult()
public void onActivityResult(int requestCode, int resultCode,
Intent returnIntent) {
// If the selection didn't work
if (resultCode != Activity.RESULT_OK) {
// Exit without doing anything else
Log.e(TAG, "Activity returned fail");
} else {
// get array list
ArrayList<Uri> uriArrayList = returnIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
// create directory in internal storage to store the assets from uri list
String toPath = this.getFilesDir().getPath();
if (uriArrayList != null) {
AssetFileDescriptor mInputAFD;
for (int i = 0; i < uriArrayList.size(); i++) {
// Get the file's content URI
Uri returnUri = uriArrayList.get(i);
try {
mInputAFD = getContentResolver().openAssetFileDescriptor(returnUri, "r");
// Get file name
String fileName = returnUri.getLastPathSegment();
Log.i(TAG, "URI " + returnUri.toString() + " fileName " + fileName);
// Create dest filename and copy
File dest = new File(toPath + "/" + fileName);
copyRaw(mInputAFD, dest);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
// Break loop at first exception
break;
}
}
}
}
}
CopyRaw method to copy the file using AssetFileDescriptor
public void copyRaw(AssetFileDescriptor fd, File destinationFile) throws IOException {
FileChannel sourceChannel = new FileInputStream(fd.getFileDescriptor()).getChannel();
FileChannel destinationChannel = new FileOutputStream(destinationFile).getChannel();
sourceChannel.transferTo(fd.getStartOffset(), fd.getLength(), destinationChannel);
}
Add Permission in Consumer manifest file
<uses-permission android:name="yourpermission" />