I can't quite get cwac to work, and looking at the demo code hasn't helped. I'm simply trying to export a pdf through a share intent. Currently the output is a "Can't attach empty file" error. But the file does exist, and I can't tell if the problem is with the file name, location, or cwac provider usage.
Here is how I've set up the provider.
<provider
android:name="com.commonsware.cwac.provider.StreamProvider"
android:authorities="com.anothergamedesigner.CatVimeoTest.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="com.commonsware.cwac.provider.STREAM_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
This is my xml resource the provider is using. I set path to "" because I don't have any subdirectories. I don't know if those are required, but ideally I don't want to have to switch up my code elsewhere for the file restructure necessary to put the files in subdirectories. Although, if that's the problem, I suppose I could, but I don't see why the root shouldn't work.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<asset name="assets" path=""/>
</paths>
Here is my PDFActivity (extends AppCompatActivity):
Variables:
private String pdfName //set in onCreate; ex. "This is my.pdf"
private static final String AUTHORITY = "com.anothergamedesigner.CatVimeoTest";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static final String ASSET_PATHS ="assets/";
Methods definitions:
private Intent getOpenPDFShareIntent(String name){
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("application/pdf");
shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));
shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setType("text/plain");
return shareIntent;
}
private Uri getURI(){
String path = ASSET_PATHS + pdfName;
return(PROVIDER
.buildUpon()
.appendPath(StreamProvider.getUriPrefix(AUTHORITY))
.appendPath(path)
.build());
}
In getURI(), an example return for System.out.println(path) is: "assets/my.pdf"
The code runs via a menu button that on selection:
Intent shareIntent = getOpenPDFShareIntent(pdfName);
StartActivity(Intent.createChooser(shareIntent, getResources().getString(R.string.contact_send_mail));
EDIT:
Attempting to remove null URIPrefix:
private Uri getURI(){
//String path = ASSET_PATHS + pdfName;
if(StreamProvider.getUriPrefix(AUTHORITY) != null){
return(PROVIDER
.buildUpon()
.appendPath(StreamProvider.getUriPrefix(AUTHORITY))
.appendPath(ASSET_PATHS)
.appendPath(pdfName)
.build());
} else{
return(PROVIDER
.buildUpon()
.appendPath(ASSET_PATHS)
.appendPath(pdfName)
.build());
}
}
EDIT 2 - Testing with DocumentFile:
I used these new methods from another SO answer and altered it to return the file.
private File CopyReadAssets()
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), "my.pdf");
try
{
in = assetManager.open("my.pdf");
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
return file;
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
Then I tested using:
DocumentFile aFile = DocumentFile.fromFile(CopyReadAssets());
DocumentFile file = DocumentFile.fromSingleUri(this, getURI());
System.out.println(aFile.getName());
System.out.println(aFile.length());
System.out.println(file.getName());
System.out.println(file.length());
It returns "my.pdf" and "33528" for aFile and "my.pdf" and "FileNotFoundException" for file.
content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Support%201.6.compressed.pdf
There are two problems here that I can see.
First, StreamProvider.getUriPrefix(AUTHORITY) is returning null. I don't know why, as you do not appear to be subclassing StreamProvider. That being said, you should check for null and skip that appendPath() statement if it is null.
Second, rather than ASSET_PATHS + pdfName, use two appendPath() statements. This should prevent the / from being converted into %2F.
Note that I have not tried files with spaces in the name, or anything else that has to get escaped, as you have in your filename. It's possible that there are bugs related to this. If changing the two items above do not help, try renaming the PDF temporarily to something simple. If that then works, I have a bug that I'll need to fix.
FINAL CODE
The problem is seems was with ASSET_PATHS. Appending the pdfName to "assets" proved to be problematic for some reason. Because of this I chose to change ASSET_PATHS from a final and then set it in the onCreate method. This would be one way to do it, or you could hard code in the different pdfs such as in the demo project.
public class PDFViewActivity extends AppCompatActivity {
private String pdfName;
...
private static final String AUTHORITY = "com.your.provider";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static String ASSET_PATHS;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
pdfName = extras.getString("pdfName");
...
ASSET_PATHS = "assets/" + pdfName;
// Place an PDFViewFragment as our content pane
PDFViewFragment f = new PDFViewFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_pdf, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.menu_button_share:
Intent shareIntent = getOpenPDFShareIntent();
startActivity(Intent.createChooser(shareIntent, "Send Email"));
return true;
...
default:
return super.onOptionsItemSelected(item);
}
}
private Intent getOpenPDFShareIntent(){
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("application/pdf");
shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));
shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
return shareIntent;
}
private Uri getURI(){
return(PROVIDER
.buildUpon()
.appendPath(StreamProvider.getUriPrefix(AUTHORITY))
.appendPath(ASSET_PATHS)
.build());
}
}
Related
i'm getting a pdf file from an api, and i got something like that http://x/docs/document1
In my android project, i have like this:
try{
Android.Content.Intent activity = new Android.Content.Intent(this, typeof(WebViewPDF));
activity.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission);
activity.AddFlags(Android.Content.ActivityFlags.NoHistory);
string uriAndroid = "http://x/docs/document1";
activity.PutExtra("url", JsonConvert.SerializeObject(uriAndroid));
StartActivity(activity);
}catch (Exception){
...
}
The main problem is, i cannot modify the api, so the endpoint is http://x/docs/document1, but if i try another uri, with the .pdf extension, for example https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf it works fine.
I don't know if i need to get that info from the API in a different way,
How can i show the pdf in the webView or external app without download first the doc?
The solution was download first and then open from local.
void PrintPdf(Uri uri)
{
var webClient = new WebClient();
webClient.Proxy = WebRequest.DefaultWebProxy;
webClient.Credentials = new NetworkCredential("UserName", "Pass");
webClient.Encoding = Encoding.UTF8;
var bytes = webClient.DownloadData(uri);
var text = bytes; // get the downloaded text
string localFilename = "NameforPdf.PDF";
string localPath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString(), localFilename);
File.WriteAllBytes(localPath, text); // writes to local storage
bool exists = File.Exists(localPath);
if (exists)
{
Java.IO.File file = new Java.IO.File(localPath);
file.SetReadable(true);
//That's the important part, notice the content://
Android.Net.Uri uriLocal = Android.Net.Uri.Parse("content://" + localPath);
Intent intent = new Intent(Intent.ActionView);
intent.SetFlags(ActivityFlags.NewTask);
intent.SetDataAndType(uriLocal, "application/pdf");
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
try
{
StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "pdf reader not installed", ToastLength.Short).Show();
}
}
}
I am creating a file to send as an attachment to an email. Now I want to delete the image after sending the email. Is there a way to delete the file?
I have tried myFile.delete(); but it didn't delete the file.
I'm using this code for Android, so the programming language is Java using the usual Android ways to access the SD card. I am deleting the file in the onActivityResult method, when an Intent is returned to the screen after sending an email.
File file = new File(selectedFilePath);
boolean deleted = file.delete();
where selectedFilePath is the path of the file you want to delete - for example:
/sdcard/YourCustomDirectory/ExampleFile.mp3
Also you have to give permission if you are using >1.6 SDK
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
in AndroidManifest.xml file
Change for Android 4.4+
Apps are not allowed to write (delete, modify ...) to external storage except to their package-specific directories.
As Android documentation states:
"Apps must not be allowed to write to secondary external storage
devices, except in their package-specific directories as allowed by
synthesized permissions."
However nasty workaround exists (see code below). Tested on Samsung Galaxy S4, but this fix does't work on all devices. Also I wouldn’t count on this workaround being available in future versions of Android.
There is a great article explaining (4.4+) external storage permissions change.
You can read more about workaround here.
Workaround source code is from this site.
public class MediaFileFunctions
{
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static boolean deleteViaContentProvider(Context context, String fullname)
{
Uri uri=getFileUri(context,fullname);
if (uri==null)
{
return false;
}
try
{
ContentResolver resolver=context.getContentResolver();
// change type to image, otherwise nothing will be deleted
ContentValues contentValues = new ContentValues();
int media_type = 1;
contentValues.put("media_type", media_type);
resolver.update(uri, contentValues, null, null);
return resolver.delete(uri, null, null) > 0;
}
catch (Throwable e)
{
return false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static Uri getFileUri(Context context, String fullname)
{
// Note: check outside this class whether the OS version is >= 11
Uri uri = null;
Cursor cursor = null;
ContentResolver contentResolver = null;
try
{
contentResolver=context.getContentResolver();
if (contentResolver == null)
return null;
uri=MediaStore.Files.getContentUri("external");
String[] projection = new String[2];
projection[0] = "_id";
projection[1] = "_data";
String selection = "_data = ? "; // this avoids SQL injection
String[] selectionParams = new String[1];
selectionParams[0] = fullname;
String sortOrder = "_id";
cursor=contentResolver.query(uri, projection, selection, selectionParams, sortOrder);
if (cursor!=null)
{
try
{
if (cursor.getCount() > 0) // file present!
{
cursor.moveToFirst();
int dataColumn=cursor.getColumnIndex("_data");
String s = cursor.getString(dataColumn);
if (!s.equals(fullname))
return null;
int idColumn = cursor.getColumnIndex("_id");
long id = cursor.getLong(idColumn);
uri= MediaStore.Files.getContentUri("external",id);
}
else // file isn't in the media database!
{
ContentValues contentValues=new ContentValues();
contentValues.put("_data",fullname);
uri = MediaStore.Files.getContentUri("external");
uri = contentResolver.insert(uri,contentValues);
}
}
catch (Throwable e)
{
uri = null;
}
finally
{
cursor.close();
}
}
}
catch (Throwable e)
{
uri=null;
}
return uri;
}
}
Android Context has the following method:
public abstract boolean deleteFile (String name)
I believe this will do what you want with the right App premissions as listed above.
Recursively delete all children of the file ...
public static void DeleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
for (File child : fileOrDirectory.listFiles()) {
DeleteRecursive(child);
}
}
fileOrDirectory.delete();
}
This works for me: (Delete image from Gallery)
File file = new File(photoPath);
file.delete();
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(photoPath))));
public static boolean deleteDirectory(File path) {
// TODO Auto-generated method stub
if( path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDirectory(files[i]);
}
else {
files[i].delete();
}
}
}
return(path.delete());
}
This Code will Help you.. And In Android Manifest You have to get Permission to make modification..
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Try this.
File file = new File(FilePath);
FileUtils.deleteDirectory(file);
from Apache Commons
Sorry: There is a mistake in my code before because of the site validation.
String myFile = "/Name Folder/File.jpg";
String myPath = Environment.getExternalStorageDirectory()+myFile;
File f = new File(myPath);
Boolean deleted = f.delete();
I think is clear...
First you must to know your file location.
Second,,, Environment.getExternalStorageDirectory() is a method who gets your app directory.
Lastly the class File who handle your file...
I had a similar issue with an application running on 4.4. What I did was sort of a hack.
I renamed the files and ignored them in my application.
ie.
File sdcard = Environment.getExternalStorageDirectory();
File from = new File(sdcard,"/ecatAgent/"+fileV);
File to = new File(sdcard,"/ecatAgent/"+"Delete");
from.renameTo(to);
This worked for me.
String myFile = "/Name Folder/File.jpg";
String my_Path = Environment.getExternalStorageDirectory()+myFile;
File f = new File(my_Path);
Boolean deleted = f.delete();
private boolean deleteFromExternalStorage(File file) {
String fileName = "/Music/";
String myPath= Environment.getExternalStorageDirectory().getAbsolutePath() + fileName;
file = new File(myPath);
System.out.println("fullPath - " + myPath);
if (file.exists() && file.canRead()) {
System.out.println(" Test - ");
file.delete();
return false; // File exists
}
System.out.println(" Test2 - ");
return true; // File not exists
}
You can delete a file as follow:
File file = new File("your sdcard path is here which you want to delete");
file.delete();
if (file.exists()){
file.getCanonicalFile().delete();
if (file.exists()){
deleteFile(file.getName());
}
}
File filedel = new File("/storage/sdcard0/Baahubali.mp3");
boolean deleted1 = filedel.delete();
Or, Try This:
String del="/storage/sdcard0/Baahubali.mp3";
File filedel2 = new File(del);
boolean deleted1 = filedel2.delete();
I have the following code that correctly attaches the image to the email and sends:
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Set tht type to image/* and add the extra text field for the message to send
sharingIntent.setType(Application2.instance().getResString(R.string.share_intent_type_text_image));
sharingIntent.putExtra(Intent.EXTRA_TEXT, String.format(Application2.instance().getResString(R.string.share_intent_body_question), question.question));
if (destFile != null)
{
Uri uri = Uri.fromFile(destFile);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
((ActivityMain) getActivity()).startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
R.string.share_intent_type_text_image is defined as "image/png"
destFile is an image grabbed from the external cache directory of the app, (((ActivityMain) getActivity()).getExternalCacheDir()
However, when I attempt to open the file in Gmail, a dialog appears that says: Info - No app can open this attachment for viewing. I've downloaded the file via my PC and the extension comes up as .File. I can open it with paint and other image viewers.
Anyone experience this before?
Considering the FileProvider problems, and also because I wanted to implement a max cache size for collected temp files, I went with a ContentProvider solution and it works a treat. Basically, you're allowed to use your internal cache without any problem but still provide third party apps with a URI they can use to reference your temporary files you want to share with them. Because you use your internal cache, there will be no unnecessary WRITE_EXTERNAL_STORAGE permission to ask for.
The added max cache size limit (that you can remove from the class by simply deleting everything from checkSize() to the end of the class, for instance, if you can make sure you delete all files directly after sharing, so they won't remain on the device) works by checking the cumulated max size upon each call and clearing up half the cache (deleting the oldest files) if necessary.
public class TemporaryFile extends ContentProvider {
private static final long MAX_SIZE = 512 * 1024;
// commented out on purpose so that you don't forget to rewrite it...
// public static final String AUTHORITY = "com.example.tempfile";
private UriMatcher uriMatcher;
#Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "*", 1);
return true;
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
if (uriMatcher.match(uri) == 1) {
final String file = getContext().getCacheDir() + File.separator + uri.getLastPathSegment();
return ParcelFileDescriptor.open(new File(file), ParcelFileDescriptor.MODE_READ_ONLY);
}
else
throw new FileNotFoundException(uri.toString());
}
#Override
public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
#Override
public int delete (Uri uri, String selection, String[] selectionArgs) {
return 0;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
public static File getFile(Context context, String prefix, String extension) throws IOException {
checkSize(context);
File file = File.createTempFile(prefix, extension, context.getCacheDir());
file.setReadable(true);
file.deleteOnExit();
return file;
}
public static Uri getPublicUri(File file) {
return Uri.withAppendedPath(Uri.parse("content://" + AUTHORITY), file.getName());
}
public static void checkSize(Context context) throws IOException {
File dir = context.getCacheDir();
if (getDirSize(dir) > MAX_SIZE)
cleanDir(dir, MAX_SIZE / 2);
}
private static long getDirSize(File dir) {
long size = 0;
for (File file : dir.listFiles())
if (file.isFile())
size += file.length();
return size;
}
private static void cleanDir(File dir, long atLeast) {
long deleted = 0;
File[] files = dir.listFiles();
Arrays.sort(files, new Comparator<File>() {
public int compare(File f1, File f2) {
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
}
});
for (File file : files) {
deleted += file.length();
file.delete();
if (deleted >= atLeast)
break;
}
}
}
Using it couldn't be simpler, just call
File file = TemporaryFile.getFile(this, "prefix", ".extension");
whenever you want to create a new file and
TemporaryFile.getPublicUri(file)
whenever you want to get a public Uri to the file, eg. to pass it to an intent as data or Intent.EXTRA_STREAM.
Being a provider, don't forget to add the necessary manifest entry, either:
<provider
android:name=".TemporaryFile"
android:authorities="com.example.tempfile"
android:exported="true"
tools:ignore="ExportedContentProvider" >
</provider>
This works but requires external storage and the relating permissions. When downloading an app, a dialog will show that the app is requesting to be able to read/write data which may turn users away. Use the FileProvider as Simon suggested in my initial post if that's a concern.
Useful links:
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
I attempted to use the File Provider as Simon suggested in my initial post to no avail. I received a NullPointerException on the following line:
final ProviderInfo info = context.getPackageManager()
.resolveContentProvider(authority, PackageManager.GET_META_DATA);
I was unable to track the problem after following the guide at:
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
as well as the other thread at:
How to use support FileProvider for sharing content to other apps?
At this point I realized there is no file type set for the images being used. I simply added .png to the files and the attachments work correctly in Gmail as well as the previous apps that already worked.
I provided the following code if anyone was curious how I shared an internal file. It's not complete and does not handle errors completely but it may be useful for someone as a start.
// Copy image file to external memory and send with the intent
File srcFile = getImage();
File destDir = new File(((ActivityMain) getActivity()).getExternalCacheDir(),
Application2.instance().getResString(R.string.temporary_external_image_path));
if(!destDir.exists())
{
destDir.mkdirs();
}
if(destDir != null && srcFile != null)
{
File destFile = new File(destDir, srcFile.getName());
if (!destFile.exists())
{
try
{
Application2.instance().copy(srcFile, destFile);
}
catch (IOException e)
{
if (BuildConfig.DEBUG) Log.e("Failed to copy file '" + srcFile.getName() + "'");
}
}
if (destFile != null)
{
Uri uri = Uri.fromFile(destFile);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
((ActivityMain) getActivity()).startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
}
I have an ImageView with a share intent( which works great, brings up all the apps I can share the image with), however, I can not share the photo because it has no path on my phone. How do I go about saving the ImageView on my phone? Below is my code.
public void taptoshare(View v)
{
View content = findViewById(R.id.myimage);
content.setDrawingCacheEnabled(true);
Bitmap bitmap = content.getDrawingCache();
File file = new File("/DCIM/Camera/image.jpg");
try
{
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, ostream);
ostream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Uri phototUri = Uri.parse("/DCIM/Camera/image.jpg");
shareIntent.setData(phototUri);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, phototUri);
startActivity(Intent.createChooser(shareIntent, "Share Via"));
}
}
UPDATE
Ok, so I figured it out. Now I have a new question, how would I go about saving this image to a new folder?
When saving and loading, you need to get the root path of the system, first. This is how I'd do it.
File root = Environment.getExternalStorageDirectory();
File cachePath = new File(root.getAbsolutePath() + "/DCIM/Camera/image.jpg");
I've come across a couple solutions which are not solving this problem.
Here is a solution that worked for me. One gotcha is you need to store the images in a shared or non app private location (http://developer.android.com/guide/topics/data/data-storage.html#InternalCache)
Many suggestions say to store in the Apps "private" cache location but this of course is not accessable via other external applications, including the generic Share File intent which is being utilised. When you try this, it will run but for example dropbox will tell you the file is no longer available.
/* STEP 1 - Save bitmap file locally using file save function below. */
localAbsoluteFilePath = saveImageLocally(bitmapImage);
/* STEP 2 - Share the non private Absolute file path to the share file intent */
if (localAbsoluteFilePath!=null && localAbsoluteFilePath!="") {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Uri phototUri = Uri.parse(localAbsoluteFilePath);
File file = new File(phototUri.getPath());
Log.d("file path: " +file.getPath(), TAG);
if(file.exists()) {
// file create success
} else {
// file create fail
}
shareIntent.setData(phototUri);
shareIntent.setType("image/png");
shareIntent.putExtra(Intent.EXTRA_STREAM, phototUri);
activity.startActivityForResult(Intent.createChooser(shareIntent, "Share Via"), Navigator.REQUEST_SHARE_ACTION);
}
/* SAVE IMAGE FUNCTION */
private String saveImageLocally(Bitmap _bitmap) {
File outputDir = Utils.getAlbumStorageDir(Environment.DIRECTORY_DOWNLOADS);
File outputFile = null;
try {
outputFile = File.createTempFile("tmp", ".png", outputDir);
} catch (IOException e1) {
// handle exception
}
try {
FileOutputStream out = new FileOutputStream(outputFile);
_bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
} catch (Exception e) {
// handle exception
}
return outputFile.getAbsolutePath();
}
/* STEP 3 - Handle Share File Intent result. Need to remote temporary file etc. */
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// deal with this with whatever constant you use. i have a navigator object to handle my navigation so it also holds all mys constants for intents
if (requestCode== Navigator.REQUEST_SHARE_ACTION) {
// delete temp file
File file = new File (localAbsoluteFilePath);
file.delete();
Toaster toast = new Toaster(activity);
toast.popBurntToast("Successfully shared");
}
}
/* UTILS */
public class Utils {
//...
public static File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file =
new File(Environment.getExternalStorageDirectory(), albumName);
if (!file.mkdirs()) {
Log.e(TAG, "Directory not created");
}
return file;
}
//...
}
I hope that helps someone.
I am creating a file to send as an attachment to an email. Now I want to delete the image after sending the email. Is there a way to delete the file?
I have tried myFile.delete(); but it didn't delete the file.
I'm using this code for Android, so the programming language is Java using the usual Android ways to access the SD card. I am deleting the file in the onActivityResult method, when an Intent is returned to the screen after sending an email.
File file = new File(selectedFilePath);
boolean deleted = file.delete();
where selectedFilePath is the path of the file you want to delete - for example:
/sdcard/YourCustomDirectory/ExampleFile.mp3
Also you have to give permission if you are using >1.6 SDK
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
in AndroidManifest.xml file
Change for Android 4.4+
Apps are not allowed to write (delete, modify ...) to external storage except to their package-specific directories.
As Android documentation states:
"Apps must not be allowed to write to secondary external storage
devices, except in their package-specific directories as allowed by
synthesized permissions."
However nasty workaround exists (see code below). Tested on Samsung Galaxy S4, but this fix does't work on all devices. Also I wouldn’t count on this workaround being available in future versions of Android.
There is a great article explaining (4.4+) external storage permissions change.
You can read more about workaround here.
Workaround source code is from this site.
public class MediaFileFunctions
{
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static boolean deleteViaContentProvider(Context context, String fullname)
{
Uri uri=getFileUri(context,fullname);
if (uri==null)
{
return false;
}
try
{
ContentResolver resolver=context.getContentResolver();
// change type to image, otherwise nothing will be deleted
ContentValues contentValues = new ContentValues();
int media_type = 1;
contentValues.put("media_type", media_type);
resolver.update(uri, contentValues, null, null);
return resolver.delete(uri, null, null) > 0;
}
catch (Throwable e)
{
return false;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static Uri getFileUri(Context context, String fullname)
{
// Note: check outside this class whether the OS version is >= 11
Uri uri = null;
Cursor cursor = null;
ContentResolver contentResolver = null;
try
{
contentResolver=context.getContentResolver();
if (contentResolver == null)
return null;
uri=MediaStore.Files.getContentUri("external");
String[] projection = new String[2];
projection[0] = "_id";
projection[1] = "_data";
String selection = "_data = ? "; // this avoids SQL injection
String[] selectionParams = new String[1];
selectionParams[0] = fullname;
String sortOrder = "_id";
cursor=contentResolver.query(uri, projection, selection, selectionParams, sortOrder);
if (cursor!=null)
{
try
{
if (cursor.getCount() > 0) // file present!
{
cursor.moveToFirst();
int dataColumn=cursor.getColumnIndex("_data");
String s = cursor.getString(dataColumn);
if (!s.equals(fullname))
return null;
int idColumn = cursor.getColumnIndex("_id");
long id = cursor.getLong(idColumn);
uri= MediaStore.Files.getContentUri("external",id);
}
else // file isn't in the media database!
{
ContentValues contentValues=new ContentValues();
contentValues.put("_data",fullname);
uri = MediaStore.Files.getContentUri("external");
uri = contentResolver.insert(uri,contentValues);
}
}
catch (Throwable e)
{
uri = null;
}
finally
{
cursor.close();
}
}
}
catch (Throwable e)
{
uri=null;
}
return uri;
}
}
Android Context has the following method:
public abstract boolean deleteFile (String name)
I believe this will do what you want with the right App premissions as listed above.
Recursively delete all children of the file ...
public static void DeleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
for (File child : fileOrDirectory.listFiles()) {
DeleteRecursive(child);
}
}
fileOrDirectory.delete();
}
This works for me: (Delete image from Gallery)
File file = new File(photoPath);
file.delete();
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(photoPath))));
public static boolean deleteDirectory(File path) {
// TODO Auto-generated method stub
if( path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDirectory(files[i]);
}
else {
files[i].delete();
}
}
}
return(path.delete());
}
This Code will Help you.. And In Android Manifest You have to get Permission to make modification..
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Try this.
File file = new File(FilePath);
FileUtils.deleteDirectory(file);
from Apache Commons
Sorry: There is a mistake in my code before because of the site validation.
String myFile = "/Name Folder/File.jpg";
String myPath = Environment.getExternalStorageDirectory()+myFile;
File f = new File(myPath);
Boolean deleted = f.delete();
I think is clear...
First you must to know your file location.
Second,,, Environment.getExternalStorageDirectory() is a method who gets your app directory.
Lastly the class File who handle your file...
I had a similar issue with an application running on 4.4. What I did was sort of a hack.
I renamed the files and ignored them in my application.
ie.
File sdcard = Environment.getExternalStorageDirectory();
File from = new File(sdcard,"/ecatAgent/"+fileV);
File to = new File(sdcard,"/ecatAgent/"+"Delete");
from.renameTo(to);
This worked for me.
String myFile = "/Name Folder/File.jpg";
String my_Path = Environment.getExternalStorageDirectory()+myFile;
File f = new File(my_Path);
Boolean deleted = f.delete();
private boolean deleteFromExternalStorage(File file) {
String fileName = "/Music/";
String myPath= Environment.getExternalStorageDirectory().getAbsolutePath() + fileName;
file = new File(myPath);
System.out.println("fullPath - " + myPath);
if (file.exists() && file.canRead()) {
System.out.println(" Test - ");
file.delete();
return false; // File exists
}
System.out.println(" Test2 - ");
return true; // File not exists
}
You can delete a file as follow:
File file = new File("your sdcard path is here which you want to delete");
file.delete();
if (file.exists()){
file.getCanonicalFile().delete();
if (file.exists()){
deleteFile(file.getName());
}
}
File filedel = new File("/storage/sdcard0/Baahubali.mp3");
boolean deleted1 = filedel.delete();
Or, Try This:
String del="/storage/sdcard0/Baahubali.mp3";
File filedel2 = new File(del);
boolean deleted1 = filedel2.delete();