@GeekDroid's answer is correct, but I thought I would provide more info to help clarify.
I've also created a library that will return the file path from an Uri
when selecting a File
from MediaStore
.
I've created a class that will copy/create a new file inside your application's directory. This is done on the background thread, as it should be done.
I have also created a callback interface to get the "status" and display a ProgressBar
Here is the interface(You can change the name and callbacks to whatever):
interface CallBackTask {
void onCopyPreExecute();
void onCopyProgressUpdate(int progress);
void onCopyPostExecute(String path, boolean wasSuccessful, String reason);
}
Here is the class to copy the file:
public class CopyFileAsyncTask extends AsyncTask<Uri, Integer, String> {
private Uri mUri;
private CallBackTask callback;
private WeakReference<Context> mContext;
private String pathPlusName;
private File folder;
private Cursor returnCursor;
private InputStream is = null;
private String errorReason = "";
DownloadAsyncTask(Uri uri, Context context, CallBackTask callback) {
this.mUri = uri;
mContext = new WeakReference<>(context);
this.callback = callback;
}
@Override
protected void onPreExecute() {
callback.onCopyPreExecute();
Context context = mContext.get();
if (context != null) {
folder = context.getExternalFilesDir("Temp");
returnCursor = context.getContentResolver().query(mUri, null, null, null, null);
try {
is = context.getContentResolver().openInputStream(mUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int post = values[0];
callback.onCopyProgressUpdate(post);
}
@Override
protected String doInBackground(Uri... params) {
File file = null;
int size = -1;
try {
try {
if (returnCursor != null && returnCursor.moveToFirst()){
if (mUri.getScheme() != null)
if (mUri.getScheme().equals("content")) {
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
size = (int) returnCursor.getLong(sizeIndex);
}else if (mUri.getScheme().equals("file")) {
File ff = new File(mUri.getPath());
size = (int) ff.length();
}
}
}
finally {
if (returnCursor != null)
returnCursor.close();
}
pathPlusName = folder + "/" + getFileName(mUri, mContext.get());
file = new File(folder + "/" + getFileName(mUri, mContext.get()));
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream fos = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
int count;
while ((count = bis.read(data)) != -1) {
if (!isCancelled()) {
total += count;
if (size != -1) {
publishProgress((int) ((total * 100) / size));
}
fos.write(data, 0, count);
}
}
fos.flush();
fos.close();
} catch (IOException e) {
errorReason = e.getMessage();
}
return file.getAbsolutePath();
}
private String getFileName(Uri uri, Context context) {
String result = null;
if (uri.getScheme() != null) {
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getPath();
assert result != null;
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
protected void onPostExecute(String result) {
if(result == null){
callback.onCopyPostExecute(pathPlusName, false, errorReason);
}else {
callback.onCopyPostExecute(pathPlusName, true, "");
}
}
}
In your Activity
you should do the following:
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleActivity extends AppCompatActivity implements CallBackTask{
Button someBtn;
Uri someUri = .... //This is just an example, you should provide your own Uri
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
someBtn = findViewById(R.id.someBtn);
someBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CopyFileAsyncTask asyntask = new CopyFileAsyncTask(someUri, ExampleActivity.this, ExampleActivity.this);
asyntask.execute();
}
});
}
ProgressBar mProgressBar;
TextView percentText;
private AlertDialog mdialog;
@Override
public void onCopyPreExecute() {
final AlertDialog.Builder mPro = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.myDialog));
@SuppressLint("InflateParams") final View mPView = LayoutInflater.from(this).inflate(R.layout.dailog_layout, null);
percentText = mPView.findViewById(R.id.percentText);
mProgressBar = mPView.findViewById(R.id.mProgressBar);
mProgressBar.setMax(100);
mPro.setView(mPView);
mdialog = mPro.create();
mdialog.show();
}
@Override
public void onCopyProgressUpdate(int progress) {
String progressPlusPercent = progress + "%";
percentText.setText(progressPlusPercent);
mProgressBar.setProgress(progress);
}
@Override
public void onCopyPostExecute(String path, boolean wasSuccessful, String reason) {
if (mdialog != null && mdialog.isShowing()) {
mdialog.cancel();
}
if (wasSuccessful){
Toast.makeText(this, "File was created at - "+path, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Error - "+reason, Toast.LENGTH_SHORT).show();
}
}
}
You can cancel the copying of the file at any time, by calling:
if (asyntask!=null){
asyntask.cancel(true);
}
If you want to implement it exactly as I did and display a ProgressBar
while the file is being copied, then here is the layout and style of my dialog:
R.style.myDialog
:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="myDialog" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:windowNoTitle">true</item>
<item name="android:background">#fff</item>
<item name="android:windowBackground">@null</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
</resources>
R.layout.dailog_layout
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/loadContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="20dp">
<RelativeLayout
android:id="@+id/dotRel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/percentText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="15dp"
android:text="0 %"
android:textColor="@android:color/black"
android:textSize="25sp" />
<ProgressBar
android:id="@+id/mProgressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_below="@+id/percentText"
android:progressDrawable="@drawable/progressbar" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
Here is the dialog while the file is being copied:

Conclusion:
With the above, your file will be copied to /storage/emulated/0/Android/data/yourPackageName/files/Temp/YourFile.jpg
. While the files are being copied a progress dialog will be displayed indicating the progress as a percentage (this is useful for when copying large files). If there was an error while copying the file, the reason will be provided in onCopyPostExecute
This will work with file and content Uri's.