I'm trying to create an app in Android, and part of it's functionality is renaming .jpg file extensions to .jpeg file extensions. However, it's not working.
filepath is the path of the .jpg file, and doThings() is what it does after the file has been renamed.
Here is my code:
// Create new string to store edited file path
String newfilepath = filepath;
// Create new file to be used for renaming
File file1 = new File(filepath);
// Remove JPG extension
newfilepath = newfilepath.substring(0, newfilepath.length() - 3);
// Replace with JPEG extension
newfilepath += "jpeg";
// Add new file for renaming purposes
File file2 = new File(newfilepath);
// Rename file from JPG to JPEG
boolean rename = file1.renameTo(file2);
// Check if file renaming was successful
if(rename) {
// Does things
doThings(newfilepath);
}
Note: I also tried changing file1.renameTo(file2); to this:
boolean test = file1.renameTo(file2);
System.out.println("Renamed? " + test);
And received this in logcat:
I/System.out: Renamed? false
Also, to prove it's not a permissions issue, here is the AndroidManifest.xml file:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" />
And I do request permissions in the Android 6+ format here:
public void getPermissions(View view) {
String[] perms = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };
if (EasyPermissions.hasPermissions(this, perms)) {
// We have permissions, send message
Toast.makeText(this, "Select an image.", Toast.LENGTH_SHORT).show();
selectFile();
} else {
// We don't have permissions
Toast.makeText(this, "Permissions are required", Toast.LENGTH_SHORT).show();
// Ask again
ActivityCompat.requestPermissions(MainActivity.this,
perms, PERMISSIONS_MULTIPLE_REQUEST);
}
}
Help is appreciated, thanks!
EDIT: I've been testing and getting weird results. I will update this later today.
Related
I am using an Intent to capture videos in my app. My code is similar to this (adapted from https://developer.android.com/training/camera-deprecated/photobasics):
File mVideo;
private File createVideoFile() throws IOException {
#SuppressLint("SimpleDateFormat")
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmssSSS").format(new Date());
String videoFileName = "VID_" + timeStamp + ".mp4";
File storageDir = Environment.getExternalStorageDirectory();
File movies = new File(storageDir, "Movies");
if (!movies.exists() && !movies.mkdir()) { // suprisingly even this works?!
Log.e(TAG, "could not create Movies directory");
throw new IOException();
}
mCurrentVideo = new File(movies, videoFileName);
}
private final ActivityResultLauncher<Uri> requestRecordVideoLauncher =
registerForActivityResult(new ActivityResultContracts.CaptureVideo(), success -> {
if (success) {
Log.i(TAG, "successfully recorded video")
assert(mVideo.canRead());
} else {
if (!mCurrentVideo.delete()) {
Log.w(TAG, "could not delete aborted video recording");
}
}
});
public void dispatchTakeVideoIntent() {
File videoFile;
try {
createVideoFile();
} catch (IOException ex) {
Log.i(TAG, "could not create file")
return;
}
Uri videoUri = FileProvider.getUriForFile(mContext, getPackageName() + ".provider", videoFile);
requestRecordVideoLauncher.launch(videoUri);
}
I have a file provider registered with this path:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
The major difference to the code in the developer manual is that I am using a path to public external storage. Thus, videos would usually be saved to the path /storage/emulated/0/Movies/VID_{DATE}{TIME}.
Testing on different devices and emulators with different API levels (21, 30, 33) concludes that this is a legal thing to do (it does not even need any permissions to read the generated files).
From what I have read in the developer references, with scoped storage an app can still access all media files it has previously created without requesting any permission (https://developer.android.com/training/data-storage/shared/media#storage-permission-not-always-needed). Additionally, the File API can still be used to access files in external storage (https://developer.android.com/about/versions/11/privacy/storage#media-direct-file-native).
Do you think, it is a good idea to trust that this will still work in later Android versions? Is there any other way to easily record a video to external storage?
I can't seem to be able to figure out how to create a directory/file through an android app to the internal storage. I have the following code:
public class Environment extends SurfaceView implements SurfaceHolder.Callback {
public static String FILE_PATH;
//other unimportant variables
public Environment(Conext context) {
super(context);
FILE_PATH = context.getFilesDir() + "/My Dir/";
File customDir = new File(FILE_PATH);
if(!customDir.exists())
System.out.println("created my dir: " + customDir.mkdir());
File test = new File(FILE_PATH + "testFile.txt");
try {
if(!test.exists())
System.out.println("created test: " + test.createNewFile());
} catch(Exception e) {
e.printStackTrace();
}
//other unimportant stuff
}
}
I then use ES File Explorer to see if it created the file and I don't see the directory/file anywhere despite it printing out "true" for the System.out.println() calls.
What am I doing wrong?
The path where you are creating file is in apps private location. Generally you can't access it from outside. It's actually created in apps data folder. However it seems you want to write in external folder.
To write in the external storage, you must request the WRITE_EXTERNAL_STORAGE permission in your manifest file:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
code:
String folder_main = "My Dir";
File f = new File(Environment.getExternalStorageDirectory(), folder_main);
if (!f.exists()) {
f.mkdirs();
}
File test = new File(f , "testFile.txt");
Here you will find how to you will create folder/file in external storage.
Save a File on External Storage
You can try with below:
ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext());
File directory = contextWrapper.getDir(getFilesDir().getName(), Context.MODE_PRIVATE);
File file = new File(directory,”fileName”);
String data = “TEST DATA”;
FileOutputStream fos = new FileOutputStream(“fileName”, true); // save
fos.write(data.getBytes());
fos.close();
This will write file in Device's internal storage (/data/user/0/com.yourapp/)
Hope this helps!
I am trying to delete a file located at the path
/storage/714D-160A/Xender/image/Screenshot_commando.png
What I've done so far:
try{
String d_path = "/storage/714D-160A/Xender/image/Screenshot_commando.png";
File file = new File(d_path);
file.delete();
}catch(Exception e){
e.printStackTrace();
}
and the file is still at its place(Not deleted :( )
Also I've given permission in Manifest file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.STORAGE" />
public static boolean delete(final Context context, final File file) {
final String where = MediaStore.MediaColumns.DATA + "=?";
final String[] selectionArgs = new String[] {
file.getAbsolutePath()
};
final ContentResolver contentResolver = context.getContentResolver();
final Uri filesUri = MediaStore.Files.getContentUri("external");
contentResolver.delete(filesUri, where, selectionArgs);
if (file.exists()) {
contentResolver.delete(filesUri, where, selectionArgs);
}
return !file.exists();
}
Using ContentResolver to delete media files is wrong and provides many problems for the user.
You can not delete a file on the sd-card simply by deleting its information from the ContentResolver on Android versions greater than Jelly Bean(4.3).
It works only on Android versions prior to KitKat(4.4).
That's why the Android team provided DocumentProvider.
Why contentResolver.delete(...) is wrong?
1. Fills up the sd-card
When you try to delete a media file on the sd-card by the ContentResolver on Android versions greater than 4.3, the actual media file will remain untouched because the contentResolver.delete(...) approach only removes the information (name, date, path ...) of the media and you will end up having unregistered media files on your sd-card which ContentResolver has no idea about their existence anymore and that's why you couldn't see them in your gallery and you think they've been deleted with this approach while they're still there and fill up the sd-card each time the user tries to delete a media file on the sd-card.
2. Media files (Images, videos, gifs ...) will come back to the gallery
There are many apps out there especially gallery and file manager ones that will find these unregistered media files and will add them to the ContentResolver again as of their normal behavior while the user assumes his/her unwanted media files are gone.
Sure no user wants his/her assuming deleted images or videos show up in the middle of a demonstration.
So, what's the correct approach to remove media files on the sd-card?
Well, this has already been answered here with the use of DocumentProvider.
From Android 4.4 onwards, you can't write to SD card files (except in the App directory) using the normal way. You'll have to use the Storage Access Framework using DocumentFile for that.
The following code works for me:
private void deletefile(Uri uri, String filename) {
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, uri);
DocumentFile file = pickedDir.findFile(filename);
if(file.delete())
Log.d("Log ID", "Delete successful");
else
Log.d("Log ID", "Delete unsuccessful");
}
where filename is the name of the file to be deleted and uri is the URI returned by ACTION_OPEN_DOCUMENT_TREE:
private static final int LOCATION_REQUEST = 1;
private void choosePath() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivityForResult(intent, LOCATION_REQUEST);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == LOCATION_REQUEST && resultCode == Activity.RESULT_OK) {
if (resultData != null) {
Uri uri = resultData.getData();
if (uri != null) {
/* Got the path uri */
}
}
}
}
Use Environment.getExternalStorageDirectory().getAbsolutePath() instead of hard coding storage path
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
File f = new File(baseDir + "/714D-160A/Xender/image/Screenshot_commando.png");
boolean d = f.delete();
I can't rename/move my temporary file and open it
Here is the code I used to create the temporary file
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
//[...]
java.io.File tempFile = java.io.File.createTempFile("filetmp", "_handled", null);
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(responseBody); //responseBody (byte[]) not null
fos.close();
//[...]
}
Then, I (try to) save it on the disk
private void saveIntoDisk(java.io.File file) {
if (PersitencyManager.isExternalStorageWritable()) {
java.io.File dirEvent = this.getParentEvent().getDirectory();
Log.d("ROOT PATH", "" + dirEvent.getAbsolutePath());
java.io.File myNewFile = new java.io.File(dirEvent.toString() + "/"+identifiant+"_"+name);
Log.d("FILE PATH", "" + myNewFile.getAbsolutePath());
path = myNewFile.getAbsolutePath();
if (!file.renameTo(myNewFile)) {
Log.e("File Rename", "Can not rename this file"); // display on console
} else {
Log.i("File Rename", "Filed renamed successfully");
}
}
}
The way I create the parent folder :
public static java.io.File getFolderStorageDir(String folderName) {
// Get the directory for the user's public pictures directory.
java.io.File file = new java.io.File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), folderName);
if (!file.mkdirs()) {
if (!file.isDirectory()) {
Log.e("Directory_Creation", "Directory not created");
}
}
return file;
}
I get this message on my console : "Can not rename this file". file.renameTo(myNewFile) does not work..
The path seems to be good :
D/FILE PATH﹕ /storage/emulated/0/Documents/12047/4691_test.pdf
Here is my AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Result : The parent folder is created but not the file ...
Any idea about my problem ?
I found the problem..
I can't rename a file with a path that is located on other storage zone.
renameTo() : Both paths be on the same mount point. On Android, applications are
most likely to hit this restriction when attempting to copy between
internal storage and an SD card.
When I created the temporary file, I give null at the directory parameter and as Google said
directory : [...]
null for the default location for temporary files, which is taken from
the "java.io.tmpdir" system property. [...]
So my temporary directory was on internal storage than the SD Card Directory.
So, I modified the directory :
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
//[...]
java.io.File dir = new java.io.File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), folderName);
java.io.File tempFile = java.io.File.createTempFile("filetmp", "_handled", dir.getAbsolutePath());
FileOutputStream fos = new FileOutputStream(tempFile);
fos.write(responseBody); //responseBody (byte[]) not null
fos.close();
//[...]
}
Try instead of using a raw File constructor, use the method getFileStreamPath provided by the Context. That is to say, do:
File oldfile = ctx.getFileStreamPath("shoppinglists.tmp");
File newfile = ctx.getFileStreamPath("shoppinglists.csv");
oldFile.renameTo(newFile);
The problem is presumably that new File() refers to a name relative to the program's current directory, which is probably not, and certainly not guaranteed to be, the directory in which internal files are stored.
Rename a file in the internal storage
I am trying to load .gif image from external storage (pictures directory) but I am getting 'file not found exception' using the following code.
InputStream mInputStream = null;
AssetManager assetManager = getResources().getAssets();
try {
mInputStream = assetManager.open(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath().concat("/01.gif"));
} catch (IOException e) {
e.printStackTrace();
}
I have also tested using manually path but got same exception
mInputStream = assetManager.open("file:///mnt/sdcard/Android/data/com.shurjo.downloader/files/Pictures/01.gif");
There is a write/read permission from the SD card in menifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Please help me how can I open a file as InputStream from external storage. Thanks in advance.
Note: I have tested it on emulator and there is a file 01.gif under Pictures folder (please see manual path). I can create directories and put files in those directories but can not able to access those files though Input Stream.
AssetManager is for accessing the files in the assets folder of the application package. It cannot be used to access files in the external storage.
You can use the following:
final String TAG = "MyAppTag";
File picturesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File imageFile = null;
final int readLimit = 16 * 1024;
if(picturesDir != null){
imageFile = new File(picturesDir, "01.gif");
} else {
Log.w(TAG, "DIRECTORY_PICTURES is not available!");
}
if(imageFile != null){
mInputStream = new BufferedInputStream(new FileInputStream(imageFile), readLimit);
mInputStream.mark(readLimit);
} else {
Log.w(TAG, "GIF image is not available!");
}
Please also take a look at the sample code available in getExternalFilesDir
Update from : this