would whatsapp allow getting users statuses on android 11 scoped storage? - android

I am working on an application which shows the list of whatsapp status in the app. Now my questions it that after the scoped storage we can't access that specific path so what to do now? Or all the whatsapp status saver applications won't work in future?
Right now i am access the statuses folder like this.
String whatsappStatus = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/.Statuses");
But it is not working on android 11 of course.If i use
All files access
to access all files on phone google play don't allow it unless it's the last solution which is not the case here.
Is there any hope that whatsapp would store the status in public directly in future or they would allow access to that specific directly?

private void checkWhatsAppPermission(){
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
Uri wa_status_uri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia/document/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses");
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, wa_status_uri);
startActivityForResult(intent, 10001);
}
You can check a working example here.
https://play.google.com/store/apps/details?id=com.larntech.whatsappstatussaver

You should use runtime permission which is storage access framework permission read documents
Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
Uri wa_status_uri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia/document/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses");
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, wa_status_uri);
startActivityForResult(intent, 10001);

new path
String whatsappStatus = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp/WhatsApp/Media/.Statuses");
and put one condition like this
if (android.os.Build.VERSION.SDK_INT < 30) {
String whatsappStatus = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/.Statuses");
}else {
String whatsappStatus = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/media/com.whatsapp/WhatsApp/Media/.Statuses");
}

Related

How to show only local storage to Select the file in Android?

Note: all type of files
I used default Gallery Intent to show to storage but it shows the Goggle Drive Option along with local Storage
I tried the following referals but nothing works for me.
Ref:
How to let user select only local files using Intent in Android?
2 .https://stackoverflow.com/questions/27762377/android-why-intent-extra-local-only-shows-google-photos
Is it possible to hide google drive while using Intent.ACTION_GET_CONTENT in android?
Used another library, to show the only local storage, it works fine
but Requirement is, Need to show only local storage and its all file types along with file size which is not available in this library.
Kindly suggest some other library like below with showing file size
Ref:
https://github.com/codekidX/storage-chooser
https://androidexample365.com/lets-user-choose-files-in-internal-or-external-storage-with-just-few-lines-of-code/
Use the below code that will help you achieve the desired results:
val selectedUri =
Uri.parse(Environment.getExternalStorageDirectory().toString() + "/Pictures")
val intent = Intent(Intent.ACTION_PICK)
intent.data = selectedUri
intent.type = "image/*"
if (intent.resolveActivityInfo(context!!.packageManager, 0) != null) {
startActivityForResult(
intent,
101
)
} else {
// if you reach this place, it means there is no any file
// explorer app installed on your device
}

Android 11 - Read Android/data directory of all apps without legacy-request (FileManager/Backup purpose)

I would like to read Android/data so I can extract documents for backup purposes. Android 11 has changes that prohibit/limit this, but is it still possible? I don't want to use the legacy-approach (if possible).
According to this Manage all files on a storage device which talks about the MANAGE_EXTERNAL_STORAGE permission it seems Google claims it should now be impossible (at least with this method):
Apps that are granted this permission still cannot access the app-specific directories that belong to other apps because these directories appear as subdirectories of Android/data/ on a storage volume.
https://developer.android.com/training/data-storage/manage-all-files
https://developer.android.com/about/versions/11/privacy/storage#other-apps-data
Here storage#other-apps-data Google also says that apps can no longer access other apps Android/data
Access to app-specific directories on external storage
On Android 11, apps can no longer access files in any other app's dedicated, app-specific directory within external storage.
Here on stackoveflow Thoryia shows us how to ask for the permission.
But can we use it (or any other method) to read those forbidden other app-data folders, Android/data/* ?
The Android app 'Total Commander' does it (on Android 11), and it seems to be using the StorageAccessFramework Intent Intent.ACTION_OPEN_DOCUMENT_TREE to access the files (a guess based on the gui that pops up), but I havn't managed to figure out how to get that working either. Its possible Total Commander use a legacy-approach.
Pr request I've screenshots of Total Comander (TC) here on my OneDrive.
I strongly suspect TC just uses the target-29 access method, I found a list of its permissions here but cannot find which version it targets: Aptoide: TC v3.21
Your question has the same solution as when you had asked
"How can i let ACTION_OPEN_DOCUMENT_TREE open in a predifined directory?".
Well for that i had already a solution.
Tried it for DCIM and Android and such but never for Android/data.
But that works too!
You can use it not with classic file means but only with Storage Access Framework.
We will manupilate INITIAL_URI obtained from StorageManager..getPrimaryStorageVolume().createOpenDocumentTreeIntent().
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
{
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
//String startDir = "Android";
//String startDir = "Download"; // Not choosable on an Android 11 device
//String startDir = "DCIM";
//String startDir = "DCIM/Camera"; // replace "/", "%2F"
//String startDir = "DCIM%2FCamera";
// String startDir = "Documents";
String startDir = "Android/data";
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
String scheme = uri.toString();
Log.d(TAG, "INITIAL_URI scheme: " + scheme);
scheme = scheme.replace("/root/", "/document/");
startDir = startDir.replace("/", "%2F");
scheme += "%3A" + startDir;
uri = Uri.parse(scheme);
intent.putExtra("android.provider.extra.INITIAL_URI", uri);
Log.d(TAG, "uri: " + uri.toString());
((Activity) context).startActivityForResult(intent, REQUEST_ACTION_OPEN_DOCUMENT_TREE);
return;
}

Gmail 5.0 app fails with "Permission denied for the attachment" when it receives ACTION_SEND intent

My app creates mails with attachments, and uses an intent with Intent.ACTION_SEND to launch a mail app.
It works with all the mail apps I tested with, except for the new Gmail 5.0 (it works with Gmail 4.9), where the mail opens without attachment, showing the error: "Permission denied for the attachment".
There are no useful messages from Gmail on logcat. I only tested Gmail 5.0 on Android KitKat, but on multiple devices.
I create the file for the attachment like this:
String fileName = "file-name_something_like_this";
FileOutputStream output = context.openFileOutput(
fileName, Context.MODE_WORLD_READABLE);
// Write data to output...
output.close();
File fileToSend = new File(context.getFilesDir(), fileName);
I'm aware of the security concerns with MODE_WORLD_READABLE.
I send the intent like this:
public static void compose(
Context context,
String address,
String subject,
String body,
File attachment) {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("message/rfc822");
emailIntent.putExtra(
Intent.EXTRA_EMAIL, new String[] { address });
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
emailIntent.putExtra(
Intent.EXTRA_STREAM,
Uri.fromFile(attachment));
Intent chooser = Intent.createChooser(
emailIntent,
context.getString(R.string.send_mail_chooser));
context.startActivity(chooser);
}
Is there anything I do wrong when creating the file or sending the intent? Is there a better way to start a mail app with attachment? Alternatively - has someone encountered this problem and found a workaround for it?
Thanks!
I was able to pass a screenshot .jpeg file from my app to GMail 5.0 through an Intent. The key was in this answer.
Everything I have from #natasky 's code is nearly identical but instead, I have the file's directory as
context.getExternalCacheDir();
Which "represents the external storage directory where you should save cache files" (documentation)
GMail 5.0 added some security checks to attachments it receives from an Intent. These are unrelated to unix permissions, so the fact that the file is readable doesn't matter.
When the attachment Uri is a file://, it'll only accept files from external storage, the private directory of gmail itself, or world-readable files from the private data directory of the calling app.
The problem with this security check is that it relies on gmail being able to find the caller app, which is only reliable when the caller has asked for result. In your code above, you do not ask for result and therefore gmail does not know who the caller is, and rejects your file.
Since it worked for you in 4.9 but not in 5.0, you know it's not a unix permission problem, so the reason must be the new checks.
TL;DR answer:
replace startActivity with startActivityForResult.
Or better yet, use a content provider.
Use getExternalCacheDir() with File.createTempFile.
Use the following to create a temporary file in the external cache directory:
File tempFile = File.createTempFile("fileName", ".txt", context.getExternalCacheDir());
Then copy your original file's content to tempFile,
FileWriter fw = new FileWriter(tempFile);
FileReader fr = new FileReader(Data.ERR_BAK_FILE);
int c = fr.read();
while (c != -1) {
fw.write(c);
c = fr.read();
}
fr.close();
fw.flush();
fw.close();
now put your file to intent,
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
You should implement a FileProvider, which can create Uris for your app's internal files. Other apps are granted permission to read these Uris. Then, simply instead of calling Uri.fromFile(attachment), you instantiate your FileProvider and use:
fileProvider.getUriForFile(attachment);
Google have an answer for that issue:
Store the data in your own ContentProvider, making sure that other apps have the correct permission to access your provider. The preferred mechanism for providing access is to use per-URI permissions which are temporary and only grant access to the receiving application. An easy way to create a ContentProvider like this is to use the FileProvider helper class.
Use the system MediaStore. The MediaStore is primarily aimed at video, audio and image MIME types, however beginning with Android 3.0 (API level 11) it can also store non-media types (see MediaStore.Files for more info). Files can be inserted into the MediaStore using scanFile() after which a content:// style Uri suitable for sharing is passed to the provided onScanCompleted() callback. Note that once added to the system MediaStore the content is accessible to any app on the device.
Also you can try set permissions for your file:
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
And finally you can copy/store your files in external storage - permissions not needed there.
I tested it and I found out that it was definitely private storage access problem.
When you attach some file to Gmail (over 5.0) do not use the file from private storage such as /data/data/package/. Try to use /storage/sdcard.
You can successfully attach your file.
Not sure why GMail 5.0 doesn't like certain file paths (which I've confirmed it does have read access to), but an apparently better solution is to implement your own ContentProvider class to serve the file. It's actually somewhat simple, and I found a decent example here: http://stephendnicholas.com/archives/974
Be sure to add the tag to your app manifest, and include a "android:grantUriPermissions="true"" within that. You'll also want to implement getType() and return the appropriate MIME type for the file URI, otherwise some apps wont work with this... There's an example of that in the comment section on the link.
I was having this problem and finally found an easy way to send email with attachment. Here is the code
public void SendEmail(){
try {
//saving image
String randomNameOfPic = Calendar.DAY_OF_YEAR+DateFormat.getTimeInstance().toString();
File file = new File(ActivityRecharge.this.getCacheDir(), "slip"+ randomNameOfPic+ ".jpg");
FileOutputStream fOut = new FileOutputStream(file);
myPic.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
file.setReadable(true, false);
//sending email
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"zohabali5#gmail.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Recharge Account");
intent.putExtra(Intent.EXTRA_TEXT, "body text");
//Uri uri = Uri.parse("file://" + fileAbsolutePath);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(Intent.createChooser(intent, "Send email..."),12);
}catch (Exception e){
Toast.makeText(ActivityRecharge.this,"Unable to open Email intent",Toast.LENGTH_LONG).show();
}
}
In this code "myPic" is bitmap which was returned by camera intent
Step 1: Add authority in your attached URI
Uri uri = FileProvider.getUriForFile(context, ""com.yourpackage", file);
Same as your manifest file provide name
android:authorities="com.yourpackage"
Step 2`; Add flag for allow to read
myIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Open file picker form my Android activity

I'm making an Android app which stores some downloaded pdf files inside the device's SD card.
Everything works fine, but now I want to add a function to just pop up the default android file/folder browser showing the directory where my app stores all the PDF (with subdirectories in it) so that the user sees where his documents are stored and can easily browse them.
I've been throught many other SO questions and forum posts, but it seems this can only be done for music/images/contacts/etc. basically those file types which have a 'dedicated browsing system' but not with general file browsing.
I'm actually using this code:
File file = new File("/sdcard/MySorgenia/Documenti/");
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
String type = "*/*";
intent.setDataAndType(data, type);
startActivity(intent);
But this will show me a "Choose the application to complete your action" dialog with many applications such as "Music" "Gallery" etc, but no general purpose one.
Thanks!
Because In android there is no any native application which you can use as a File Explorer and responds to Intent type "*/*"
Implement your own File-Explorer Code for this purpose..
Look at these two Links..
openintents
Android-File-Explore
public void loadfile()
{
private static final int gallery=12;
private static final String type="*/*";
Intent i=new Intent(Intent.ACTION_GET_CONTENT);
i.setType(type);
startActivityForResult(Intent.createChooser(i,"select file"), gallery);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == gallery && resultCode == RESULT_OK && data != null) {
Uri uploadfileuri = data.getData();
File file = new File(uploadfileuri.getPath());
}
}
Since Android 4.4 KitKat (API level 19), there is an Android built-in file picker: your app invokes the ACTION_OPEN_DOCUMENT and/or ACTION_CREATE_DOCUMENT intent and receives the files returned by document providers. More info about that can be found here:
Open files using storage access framework | Android Developers
Depending on where you want to store files, you may need to request permission:
Request App Permissions | Android Developers
Here is a how to:
An Android Storage Access Framework Example - Techtopia.
And a great working example is Ian Lake's Local Storage. Its source can be found on GitHub:
https://github.com/ianhanniballake/LocalStorage
And the app can be downloaded from Google Play:
https://play.google.com/store/apps/details?id=com.ianhanniballake.localstorage
Most android distributions do not come with a default file browser, and the behavior you noticed is the default android behavior. If there's any good third party file browser installed, it will automatically show up in that list. However it is not guaranteed that every end user will have a file browser installed. A general purpose fragment-widget can be created for this (and probably shared with others).
Look at this file picker, it's the best one I found:

Is there a way to read local pdf file using google docs

I saw a way of reading online pdf files using google docs ...
Android - Load PDF / PDF Viewer
Is there a way we can use it to view local files stored in sd card
You can launch an intent that will allow the user to choose what app will open the PDF with the following code, which will work for any file and mimetype. If the user doesn't have an app that can open it, you can display an error or do whatever else you need to do.
Note that the file must be world-readable, so it must be marked as such if it is on Internal storage, or it must be in external storage.
private void openFile(File f, String mimeType)
{
Intent viewIntent = new Intent();
viewIntent.setAction(Intent.ACTION_VIEW);
viewIntent.setDataAndType(Uri.fromFile(file), mimeType);
// using the packagemanager to query is faster than trying startActivity
// and catching the activity not found exception, which causes a stack unwind.
List<ResolveInfo> resolved = getPackageManager().queryIntentActivities(viewIntent, 0);
if(resolved != null && resolved.size() > 0)
{
startActivity(viewIntent);
}
else
{
// notify the user they can't open it.
}
}

Categories

Resources