How to get PDF File Path In Android 11 and 12 - java

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));

Related

Android 11: Send e-mail with automatically attached file

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"));
}

Android: download/create and share file issue causing too many crashes mostly on android 10 (Android Q)

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.

Firebase StorageReference.getFile is not working - FirebaseStorage Android

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

XMLRPC Wordpress Image Upload - Uploads Empty Image?

I am trying to upload an image file to a Wordpress Site using XMLRPC.
I'm using org.apache.xmlrpc:xmlrpc-client to make the connection from Android, and I can successfully hit the website, and fire the upload, but the image file is empty on the site. I've sent through a base64 encoded string as the WP API states but I just can't get it to work?
Anyone know why?
This is my code:
public static void updatePhoto(final String status, final Context context, final String uri) {
websiteUrl = (String) loadPreference("wordpressUrl", context,String.class);
username = (String) loadPreference("wordpressUsername", context,String.class);
password = (String) loadPreference("wordpressPassword", context,String.class);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL(websiteUrl+"/xmlrpc.php"));
XmlRpcClient rpcClient = new XmlRpcClient();
rpcClient.setConfig(config);
Uri realUri = getImageContentUri(context,Uri.parse(uri).getPath());
final InputStream imageStream = context.getContentResolver().openInputStream(realUri);
Bitmap originalBitmap = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
originalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] outputByteArray = baos.toByteArray();
String base64EncodedString = Base64.encodeToString(outputByteArray, Base64.DEFAULT);
Map content = new Hashtable();
content.put("name", status+".jpg");
content.put("type", "image/jpeg");
content.put("bits", base64EncodedString);
content.put("overwrite", false);
// Make the XMLRPC call.
Object result = rpcClient.execute("wp.uploadFile", new Object[]{
0,
username,
password,
content
});
// Print result - this is the new post's ID.
System.out.println(result);
} catch (final XmlRpcException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
} catch (final Exception e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
});
}
public static Uri getImageContentUri(Context context, String absPath) {
Log.v(TAG, "getImageContentUri: " + absPath);
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
, new String[] { MediaStore.Images.Media._ID }
, MediaStore.Images.Media.DATA + "=? "
, new String[] { absPath }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , Integer.toString(id));
} else if (!absPath.isEmpty()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, absPath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
private static String encodeImage(Bitmap bm)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG,100,baos);
byte[] b = baos.toByteArray();
String encImage = Base64.encodeToString(b, Base64.NO_WRAP);
return encImage;
}

FileNotFoundException When Uploading File (Non-image) To App

I've been trying to allow the user to upload a file (PDF) to my app for eventual upload to my Parse server, but every time I attempt to create a filestream/buffered input stream, I get a FileNotFoundException, claiming that there is 'no such file or directory'. One of my logged file paths appears below:
/storage/emulated/0/Android/data/com.parse.starter/files/Eloquent_JavaScript.pdf
I have no idea as to why it's giving me this bad path. This is my MainActivity (my only activity). I understand that not all files will be stored internally on the phone -- that's why I used certain support methods for my onActivityResult class. I've been struggling to isolate my issue because I haven't been working with files for very long, so things are still relatively new to me. Again, I apologize for all the code. Any assistance is appreciated.
Intent Method
public void getFile()
{
Intent intent = new Intent();
intent.setType("application/pdf");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 1);
}
onActivityResult Method
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
filename = null;
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
try {
Uri uri = data.getData();
if (1 > 1) {
Toast.makeText(this,"The selected file is too large. Select a new file with size less than 2mb",Toast.LENGTH_LONG).show();
} else {
String mimeType = getContentResolver().getType(uri);
if (mimeType == null) {
String path = getPath(this, uri);
if (path == null) {
filename = uri.toString().substring(uri.toString().lastIndexOf("/") + 1);
} else {
File file = new File(path);
filename = file.getName();
}
} else {
Uri returnUri = data.getData();
Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
String size = Long.toString(returnCursor.getLong(sizeIndex));
}
File fileSave = getExternalFilesDir(null);
String sourcePath = getExternalFilesDir(null) + "/" + filename;
sourcePath = sourcePath.substring(sourcePath.lastIndexOf("data") + 4, sourcePath.length());
Log.i("PATH", sourcePath);
Log.i("NAME", filename);
// create byte array
File file = new File(sourcePath);
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// byte array created
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Here Are Some Support Methods for the onActivityResult method
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
All apps (root or not) have a default data directory, which is /data/data/<package_name>. By default, the apps databases, settings, and all other data go here. If an app expects huge amounts of data to be stored, or for other reasons wants to "be nice to internal storage", there's a corresponding directory on the SDCard (Android/data/<package_name>).
In your code, at this line
String sourcePath = getExternalFilesDir(null).toString() + "/" + filename;
filename is the actual path. getExternalFilesDir(null).toString() appends /storage/emulated/0/ to the start of sourcePath. Not all files are from Internal Storage. So remove it.
String sourcePath = filename;

Categories