I am trying to download a file in my AsyncTask from Firebase Storage as below:
static class DownloadFileFromFireBase extends AsyncTask<String, Void, Boolean> {
File file;
String fileName;
boolean downloadStatus = false;
public DownloadFileFromFireBase(Context context,String fileName, File file){
this.fileName = fileName;
this.file = file;
}
protected Boolean doInBackground(String... urls) {
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageRef = storage.getReference();
StorageReference dataRef = storageRef.child(fileName);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
dataRef.getFile(file).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG,"File Downloaded");
downloadStatus = true;
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Log.d(TAG,"File Download Failed");
downloadStatus = false;
}
});
return downloadStatus;
}
protected void onPostExecute(InputStream contentsInputStream) {
//TODO:
}
}
My program neither goes into addOnSuccessListener nor in addOnFailureListener listners (no logs printed in Logcat)
I have temporarily set my Firebase rules as below:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if request.auth == null;
}
}
}
I am calling my AsyncTask as below:
boolean status = new DownloadFileFromFireBase(getContext(), contentsJsonFile).execute("").get();
My files stored on the Firebase storage are accessible from web browser (where I am not logged in/an incognito mode).
My Emulator and Device are using latest Google Services.
Even Firebase Storage API implemented in my project is the latest one (19.1.1).
I am not sure what is going wrong in here.
Any help would be appreciated! Thanks.
FirebaseStorage Android SDK getFile(file) seems no longer work properly in Android Q (SDK 29) which is a breaking changes. You may use getBytes(file_size) like this.
//Member variable but depending on your scope
private ByteArrayInputStream inputStream;
private Uri downloadedFileUri;
private OutputStream stream;
//Creating a reference to the link
StorageReference httpsReference = FirebaseStorage.getInstance().getReferenceFromUrl(downloadURL);
Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String type = "";
String mime = "";
String folderName = "";
if (downloadURL.contains("jpg") || downloadURL.contains("jpeg")
|| downloadURL.contains("png") || downloadURL.contains("webp")
|| downloadURL.contains("tiff") || downloadURL.contains("tif")) {
type = ".jpg";
mime = "image/*";
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
folderName = Environment.DIRECTORY_PICTURES;
}
if (downloadURL.contains(".gif")){
type = ".gif";
mime = "image/*";
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
folderName = Environment.DIRECTORY_PICTURES;
}
if (downloadURL.contains(".mp4") || downloadURL.contains(".avi")){
type = ".mp4";
mime = "video/*";
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
folderName = Environment.DIRECTORY_MOVIES;
}
if (downloadURL.contains(".mp3")){
type = ".mp3";
mime = "audio/*";
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
folderName = Environment.DIRECTORY_MUSIC;
}
final String relativeLocation = folderName + "/" + getString(R.string.app_name);
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, UUID.randomUUID().toString() + type);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mime); //Cannot be */*
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
ContentResolver resolver = getContentResolver();
Uri uriResolve = resolver.insert(contentUri, contentValues);
try {
if (uriResolve == null || uriResolve.getPath() == null) {
throw new IOException("Failed to create new MediaStore record.");
}
stream = resolver.openOutputStream(uriResolve);
//This is 1GB change this depending on you requirements
httpsReference.getBytes(1024 * 1024 * 1024)
.addOnSuccessListener(bytes -> {
try {
int bytesRead;
inputStream = new ByteArrayInputStream(bytes);
while ((bytesRead = inputStream.read(bytes)) > 0) {
stream.write(bytes, 0, bytesRead);
}
inputStream.close();
stream.flush();
stream.close();
//FINISH
} catch (IOException e) {
closeSession(resolver, uriResolve, e);
e.printStackTrace();
Crashlytics.logException(e);
}
});
} catch (IOException e) {
closeSession(resolver, uriResolve, e);
e.printStackTrace();
Crashlytics.logException(e);
}
A better replacement if you want to monitor the download progress is by using getStream(), with this you can compute the downloaded bytes from total bytes to download.
httpsReference.getStream((state, inputStream) -> {
long totalBytes = state.getTotalByteCount();
long bytesDownloaded = 0;
byte[] buffer = new byte[1024];
int size;
while ((size = inputStream.read(buffer)) != -1) {
stream.write(buffer, 0, size);
bytesDownloaded += size;
showProgressNotification(bytesDownloaded, totalBytes, requestCode);
}
// Close the stream at the end of the Task
inputStream.close();
stream.flush();
stream.close();
}).addOnSuccessListener(taskSnapshot -> {
showDownloadFinishedNotification(downloadedFileUri, downloadURL, true, requestCode);
//Mark task as complete so the progress download notification whether success of fail will become removable
taskCompleted();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, false);
resolver.update(uriResolve, contentValues, null, null);
}).addOnFailureListener(e -> {
Log.w(TAG, "download:FAILURE", e);
try {
stream.flush();
stream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
FirebaseCrashlytics.getInstance().recordException(ioException);
}
FirebaseCrashlytics.getInstance().recordException(e);
//Send failure
showDownloadFinishedNotification(null, downloadURL, false, requestCode);
//Mark task as complete
taskCompleted();
});
Check the sample project to learn more: https://github.com/firebase/quickstart-android/tree/master/storage
Related
I tried much code for getting pdf path in android 11 or 12 but only working in android 10 or below devices.
Can you please help me? I share my code of lines
Intent calling like this
Intent intent = new Intent();
intent.setType("application/pdf");
statusAdapter = "pdf";
pos = position;
intent.setAction(Intent.ACTION_GET_CONTENT);
someActivityResultLauncher.launch(Intent.createChooser(intent, "Select PDF"));
someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
if (data == null) {
//error
return;
}
try {
final Uri pdfUri= data.getData();
File pdfFile = new File(getPath(pdfUri));
long length = pdfFile.length();
length = length / 1024;
Toast.makeText(CreateSubEventActivity.this, "File Path : " + pdfFile.getPath() + ", File size : " + length + " KB", Toast.LENGTH_SHORT).show();
// uploadFile(imageFile);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(CreateSubEventActivity.this, "Something went wrong", Toast.LENGTH_LONG).show();
}
}
});
getPath calling like this
public String getPath(Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor == null) return null;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
cursor.close();
return s;
}
If you want to access a File or want a file path from a Uri that was returned from MediaStore, I have got a library that handles all the exceptions you might get. This includes all files on the disk, internal and removable disk. When selecting a File from Dropbox, for example, the File will be copied to your applications directory where you have full access, the copied file path will then be returned.
Let me share my experience to fix this stuff after so reading all.
Get input stream from URI
final Uri pdfUri= data.getData();
getContentResolver().openInputStream(pdfUri)
then do your stuff with InputStream, like I have uploaded pdf using okHttp
try {
RequestBody pdffile = new RequestBody() {
#Override public MediaType contentType() { return MediaType.parse("application/pdf"); }
#Override public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
#Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
};
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", "fname.pdf", pdffile)
//.addFormDataPart("Documents", value) // uncomment if you want to send Json along with file
.build();
Request request = new Request.Builder()
.url(serverURL)
.post(requestBody)
.build();
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(180, TimeUnit.SECONDS).readTimeout(180, TimeUnit.SECONDS)
.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder builder = original.newBuilder().method(original.method(), original.body());
builder.header("key", key);
return chain.proceed(builder.build());
})
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(final Call call, final IOException e) {
// Handle the error
setIsLoading(false);
getNavigator().uploadIssue("Facing some issue to upload this file.");
}
#Override
public void onResponse(final Call call, final Response response) throws IOException {
setIsLoading(false);
if (!response.isSuccessful()) {
getNavigator().uploadIssue("Facing some issue to upload this file.");
}else {
// Upload successful
getNavigator().uploadedSucessfully();
}
}
});
return true;
} catch (Exception ex) {
// Handle the error
ex.printStackTrace();
}
This one helps in my case on Android 11 hope anyone gets this helpful
private String copyFile(Uri uri, String newDirName) {
Uri returnUri = uri;
Cursor returnCursor = this.getContentResolver().query(returnUri, new String[]{
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
}, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File output;
if (!newDirName.equals("")) {
File dir = new File(this.getFilesDir() + "/" + newDirName);
if (!dir.exists()) {
dir.mkdir();
}
output = new File(this.getFilesDir() + "/" + newDirName + "/" + name);
} else {
output = new File(this.getFilesDir() + "/" + name);
}
try {
InputStream inputStream = this.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(output);
int read = 0;
int bufferSize = 1024;
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return output.getPath();
}
String newPath = copyFileToInternalStorage(uri, getResources().getString(R.string.app_name));
I want open and email app with already generated text, subject, recipient and attached file, it works with android sdk version 29 (android 10) and lower. However starting Android 11 there are restriction to writing file in external or internal storages, and there is also another restriction that is not allowed to attach file automatically from app file directory.
Previously I was copying from app storage to internal or external storage to attach file, any solutions?
done
android:requestLegacyExternalStorage="true"
public static void sendMail(Context context) throws IOException {
Context appContext = context.getApplicationContext();
File logFile = FileUtils.createFile(context.getFilesDir().getAbsolutePath(), "testFile.txt", "Test");
File logsDirectory = new File(FileUtils.getStorageDirectory(appContext), "files");
logsDirectory.mkdirs();
File destFile = new File(logsDirectory, "log.txt");
InputStream in = new FileInputStream(logFile);
boolean copied = FileUtils.copyToFile(in, destFile);
Uri logPath = Uri.fromFile(destFile);
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// set the type to 'email'
emailIntent.setData(Uri.parse("mailto:"));
String[] to = {"support#test.com"};
String subject = "Test log";
String body =
"Hello";
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
// the attachment
emailIntent.putExtra(Intent.EXTRA_STREAM, logPath);
context.startActivity(Intent.createChooser(emailIntent, "Send email..."));
}
public class FileUtils {
public static String getExtensionFromFileName(String fileName) {
if (fileName == null) return null;
String extension = null;
int i = fileName.lastIndexOf('.');
if (i > 0) {
extension = fileName.substring(i + 1);
}
return extension;
}
/**
* Copy data from a source stream to destFile. Return true if succeed, return false if failed.
*/
public static boolean copyToFile(InputStream inputStream, File destFile) {
if (inputStream == null || destFile == null) return false;
try {
try (OutputStream out = new FileOutputStream(destFile)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
}
return true;
} catch (IOException e) {
Log.e("[File Utils]", "copyToFile exception: " + e);
}
return false;
}
public static String getStorageDirectory(Context mContext) {
String storageDir =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/"
+ mContext.getString(R.string.app_name);
File file = new File(storageDir);
mContext.getExternalMediaDirs();
if (!file.isDirectory() || !file.exists()) {
}
return storageDir;
}
public static File createFile(String directory ,String fileName, String textToAttach)
{
File logFile = new File(directory + "/" + fileName);
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(textToAttach);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return logFile;
}
}
I have done using FileProvider and selector, this is for multiple files
public static void sendMail(Context context) {
Context appContext = context.getApplicationContext();
final String authority = appContext.getPackageName() + ".FileProvider";
String[] to = {"test#test.com"};
String subject = "subject";
String body = "body";
ArrayList<File> logFiles = getLogFile(context);
if (logFiles.size() == 0) {
Toast.makeText(
context,
context.getString(R.string.toast_send_failed_no_file_found),
Toast.LENGTH_LONG)
.show();
return;
}
// has to be an ArrayList
ArrayList<Uri> logPaths = new ArrayList<>();
for (File file : logFiles) {
if (file.exists()) {
logPaths.add(FileProvider.getUriForFile(appContext, authority, file));
}
}
Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
emailSelectorIntent.setDataAndType(Uri.parse("mailto:"), "plain/text");
final Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
// emailIntent.setType("plain/text");
emailIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, logPaths);
emailIntent.setSelector(emailSelectorIntent);
context.startActivity(Intent.createChooser(emailIntent, "Send Logs"));
}
I have an android application which allows user to create, download, and share content like images, videos, etc.
Recently I have provided updated with API version 29 and it is causing too many crashes on my app while downloading and sharing files. Most of them are like
Fatal Exception: java.lang.NullPointerException Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null
object reference
Fatal Exception: java.lang.NullPointerException Attempt to invoke
virtual method 'java.lang.String java.io.File.getAbsolutePath()' on a
null object reference
There are a total of two class that I use to download and share files one is written in java and other is written in kotlin, so basically I get URL of the file to pass it to my downloader task and then share URI/bitmap after download gets complete to my ShareUtil class from there I share files.
Below is code where I start download task:
if (!UserStatus.isStoragePermissionGranted(DetailImageNew.this)) {
checkPermission();
} else if (!UserStatus.isNetworkConnected(DetailImageNew.this)) {
Toasty.warning(DetailImageNew.this.getApplicationContext(), DetailImageNew.this.getResources().getString(R.string.downloadingoffline), Toast.LENGTH_SHORT, true).show();
mainImage.setDrawingCacheEnabled(true);
Bitmap scaledBitmap = mainImage.getDrawingCache();
other = 1;
ShareUtil.shareImage(scaledBitmap, DetailImageNew.this, catshare);
} else {
if (!maindownloading) {
maindownloading = true;
MyDownloadTask.DownloadListener downloadListener = new MyDownloadTask.DownloadListener() {
#Override
public void status(boolean downloading) {
((Activity) DetailImageNew.this).runOnUiThread(new Runnable() {
public void run() {
if (downloading) {
relative_layout_progress_fragement_video.setVisibility(View.VISIBLE);
} else {
relative_layout_progress_fragement_video.setVisibility(View.GONE);
}
}
});
}
#Override
public void downlodedFile(#NotNull File file) {
sharefile = file;
DetailImageNew.this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(sharefile)));
}
#Override
public void onDownloadComplete(boolean download, int pos) {
maindownloading = false;
other = 1;
ShareUtil.share(DetailImageNew.this, sharefile,catshare);
Toasty.success(getApplicationContext(), getResources().getString(R.string.images_downloaded), Toast.LENGTH_SHORT, true).show();
}
#Override
public void downloadProgress(int status) {
((Activity) DetailImageNew.this).runOnUiThread(new Runnable() {
public void run() {
progress_bar_fragement_video.setProgress(status);
text_view_progress_fragement_video.setText(DetailImageNew.this.getResources().getString(R.string.downloading) + " " + status + " %");
}
});
}
};
String basename = FilenameUtils.getName(statusRead.getStatus());
new MyDownloadTask(DetailImageNew.this, statusRead.getStatus(), basename, 1, downloadListener).execute(true);
} else {
Toasty.warning(DetailImageNew.this.getApplicationContext(), DetailImageNew.this.getResources().getString(R.string.downloadingoffline), Toast.LENGTH_SHORT, true).show();
}
}
so here I share the file using MyDownloadTask kotlin class, code of MyDownloadTask as below:
class MyDownloadTask ( #SuppressLint("StaticFieldLeak") val context: Context,
val yourUrl: String,
val fileName: String,
val position: Int,
val listener: DownloadListener
) : AsyncTask<Boolean, Void, Boolean>() {
override fun doInBackground(vararg booleans: Boolean?): Boolean {
var lenghtOfFile: Long = 0
var status = 0
val client = OkHttpClient()
val request = Request.Builder()
.url(yourUrl)
.build()
var response: Response? = null
try {
response = client.newCall(request).execute()
} catch (e: IOException) {
e.printStackTrace()
}
val inputStream: InputStream
try {
lenghtOfFile = response!!.body!!.contentLength()
} catch (e: Exception) {
}
try {
assert(response!!.body != null)
inputStream = response!!.body!!.byteStream()
val buff = ByteArray(1024 * 4)
var downloaded: Long = 0
val folder =
File(Environment.getExternalStorageDirectory().toString() + "/APPNAME/")
if (!folder.exists()) {
folder.mkdir()
}
val documentFile = File("$folder/$fileName")
documentFile.parentFile.mkdirs()
try {
documentFile.createNewFile()
} catch (e: IOException) {
e.printStackTrace()
}
var output: OutputStream? = null
try {
output = FileOutputStream(documentFile, false)
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
while (true) {
val readed = inputStream.read(buff)
if (readed == -1) {
break
}
if (isCancelled) {
break
}
downloaded += readed.toLong()
status = (downloaded * 100 / lenghtOfFile).toInt()
listener.downloadProgress(status)
output!!.write(buff, 0, readed)
}
output!!.flush()
val file: File
listener.downlodedFile(documentFile)
listener.status(false)
output.close()
return true
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
override fun onPreExecute() {
super.onPreExecute()
listener.status(true)
}
override fun onProgressUpdate(vararg values: Void) {
super.onProgressUpdate(*values)
}
override fun onPostExecute(objects: Boolean?) {
super.onPostExecute(objects)
if (objects!!) {
listener.onDownloadComplete(true, position)
} else {
listener.onDownloadComplete(false, position)
}
}
override fun onCancelled(aBoolean: Boolean?) {
super.onCancelled(aBoolean)
val folder = File(Environment.getExternalStorageDirectory().toString() + "/APPNAME/")
val documentFile = File("$folder/$fileName")
documentFile.delete()
}
override fun onCancelled() {
super.onCancelled()
}
public interface DownloadListener {
fun onDownloadComplete(download: Boolean, pos: Int)
fun downloadProgress(status: Int)
fun downlodedFile(file: File)
fun status(state: Boolean)
}
}
After file download gets complete I share the file to my ShareUtil Class as:
public static void share(Context context, File file, String catshare) {
Bitmap image = BitmapFactory.decodeFile(file.getAbsolutePath());
shareImage(image, context, catshare);
}
public static String shareImage(Bitmap image, Context mContext, String shareurl) {
Bitmap picture = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher);
image = overlayCustom(image, mContext, 0, 0);
String savedImagePath = null;
Uri bmpUri = null;
String imageFileName = "EHS_" + new Date().getTime() + ".jpg";
File storageDir = new File(
Environment.getExternalStorageDirectory().getAbsolutePath() + "/APPNAME");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
bmpUri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID, imageFile);
} catch (Exception e) {
e.printStackTrace();
}
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, "" + "" +
"\n\n" + UserStatus.getConfig(mContext).getSharestring() + " :- " + shareurl);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(Intent.createChooser(shareIntent, "APPNAME"));
}
return savedImagePath;
}
public static Bitmap overlayCustom(Bitmap bmp1, Context context, int ci, int what) {
String appname = "";
if (what == 0)
appname = context.getResources().getString(R.string.kanmani);
else
appname = context.getResources().getString(R.string.kanmani);
Bitmap picture = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher_white);
bmp1 = overlayBitmapToBottom(bmp1, picture, context, bmp1.getConfig(), appname);
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, new Matrix(), null);
return bmOverlay;
}
for sharing file without internet code is like:
public static String shareImage(Bitmap image, Context mContext, String shareurl) {
Bitmap picture = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher);
image = overlayCustom(image, mContext, 0, 0);
String savedImagePath = null;
Uri bmpUri = null;
String imageFileName = "EHS_" + new Date().getTime() + ".jpg";
File storageDir = new File(
Environment.getExternalStorageDirectory().getAbsolutePath() + "/APPNAME");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
bmpUri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID, imageFile);
} catch (Exception e) {
e.printStackTrace();
}
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, "" + "" +
"\n\n" + UserStatus.getConfig(mContext).getSharestring() + " :- " + shareurl);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(Intent.createChooser(shareIntent, "APPNAME"));
}
return savedImagePath;
}
I have already followeds guideline for Android Q for file sharing like:
Added line for requestLegacyExternalStorage in the manifest file.
Using FileProvider
The same error is also happening on android versions less than 10 (Q) many times.
While testing I never got these errors at all but anyhow these errors coming to production and I am not able to reproduce them at my end.
Please help me as these errors are causing too many crashes in my production release.
I have the following Java code which downloads an image from an URL.
I can see the image downloaded in the folder, but the image does not appear in gallery. Only if I restart phone, Samsung S7 with android 7, I can see images in gallery. What can I do to have the images in gallery in real time after I downloaded them?
public class DetailsImgActivity extends AppCompatActivity {
private static final String TAG = "DetailsImgActivity";
private ImageView imageViewPoze;
private Button buttonDownload;
private static final int PERMISSION_REQUEST_CODE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details_img);
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
// image url stored in imageID
final String imageId = getIntent().getStringExtra("ImageId");
imageViewPoze = findViewById(R.id.imageViewPozeC);
Picasso.get().load(imageId).into(imageViewPoze);
buttonDownload = findViewById(R.id.btn_Download_Img);
buttonDownload.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
downloadFile(imageId);
}
});
}
private void downloadFile(String url) {
Retrofit.Builder builder = new Retrofit.Builder().baseUrl("https://firebasestorage.blabla.com/");
Retrofit retrofit = builder.build();
FileDownloadClient fileDownloadClient = retrofit.create(FileDownloadClient.class);
Call<ResponseBody> call = fileDownloadClient.downloadFile(url);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, final Response<ResponseBody> response) {
// if (response.isSuccess()) {
Log.d(TAG, "server contacted and has file");
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
boolean writtenToDisk = writeResponseBodyToDisk(response.body());
return null;
}
}.execute();
//after the image has been downloaded -refresh gallery
**Toast.makeText(getApplicationContext(), "File downloaded with success!", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File("file://"+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
else
{
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}**
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(TAG, "error");
}
});
}
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
String folder_main = Constants.dirName;
File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), folder_main);
if (!f.exists()) {
f.mkdirs();
}
// todo change the file location/name according to your needs
File futureStudioIconFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM+"/"+ Constants.dirName)
+ File.separator + UUID.randomUUID()+".jpg");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
}
I used the follwing code, but If I don't reboot phone, I can't see the picture in gallery.
**Toast.makeText(getApplicationContext(), "File downloaded with success!", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File("file://"+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
else
{
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}**
Here is the code:
public void Displayimg(View v) {
File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");
ipath[0] = String.valueOf(((TextView) v).getText());
String sifile = ipath[0].substring(45,52); // extracting the filename from the view eg: abc.jpg
File imgfile = new File(path,sifile); // it fails on this line with unfortunately, main application has stopped.
// if the sifile conatians a name of the file that exist, it give error and comes out
// if I give file name in sifile that does not exisit, if give file does on exisit and comes our with error.
// Basically I am having problem to open an image file that exisit and dispaly.
// File("/storage/sdcard0/Pictures/MyCameraApp/Zimg20151105_1535133.Jpg");
Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
ImageView myImage = (ImageView) findViewById(R.id.mc_imgview);
if(imgfile.exists()){
Toast.makeText(getApplicationContext(),file.getAbsolutePath() + "File Exisit", Toast.LENGTH_SHORT).show();
myImage.setImageBitmap(myBitmap);
}
else
{
Toast.makeText(getApplicationContext(),file.getAbsolutePath() + " File Does not Exisit", Toast.LENGTH_SHORT).show();
}
}
Display image :
Try to Search Volley or Universal-Image-Loader or Glide.
Save Image:
public static String getSdPath(){
//todo test path
return Environment.getExternalStorageDirectory().getAbsolutePath();
// return "";
}
public static String getImageDir (String type,Activity activity){
if(type.equalsIgnoreCase("pure")){
return getSdPath()+ activity.getDir("pure", Context.MODE_PRIVATE).getAbsolutePath();
}else{
return getSdPath()+activity.getDir("deal", Context.MODE_PRIVATE).getAbsolutePath();
}
}
private static final String APPLICATION_NAME = "test";
private static final Uri IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
private static final String PATH = getImageDir("deal", mActivity);
public static Uri savePngImage(ContentResolver cr, Bitmap bitmap) {
long dateTaken = System.currentTimeMillis();
String name = String.valueOf(dateTaken) + ".png";
return savePngImage(cr, name, dateTaken, PATH, name, bitmap);
}
public static Uri savePngImage(ContentResolver cr, String name, long dateTaken, String directory,
String filename, Bitmap source) {
OutputStream outputStream = null;
String filePath = directory + File.separator + filename;
try {
File dir = new File(directory);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(directory, filename);
if (file.createNewFile()) {
outputStream = new FileOutputStream(file);
if (source != null) {
source.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
} else {
}
}
// FileUtils.updateFile(file);
} catch (FileNotFoundException ex) {
return null;
} catch (IOException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
}
}
}
ContentValues values = new ContentValues(7);
values.put(MediaStore.Images.Media.TITLE, name);
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATA, filePath);
// FileUtils.updateFile(filePath);
return cr.insert(IMAGE_URI, values);
}