Im facing a problem when creating app custom folder. like
com.app and storage/.hideFolder etc.
by using some of approaches below android 11 (SDK API 30) device
it's working fine but in android 11. not able to make it im using an approach which is shown below
public static String root= Environment.getExternalStorageDirectory().toString();
public static final String app_hided_folder ="/.HidedAPPTop/";
public static final String app_showing_folder ="/APPTop/";
public static final String draft_app_folder= app_hided_folder +"Draft/";
public static void make_directry(String path,Context context) {
File dir = new File(path);
if (!dir.exists())
Toast.makeText(context,
(dir.mkdirs() ? "Directory has been created" : "Directory not created"),
Toast.LENGTH_SHORT).show();
else
Toast.makeText(context, "Directory exists", Toast.LENGTH_SHORT).show();
}
Function calling
make_directry(Variables.app_hided_folder,getContext());
Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
…
android:requestLegacyExternalStorage="true"
…
>
2nd question
public static String root=
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS
).toString();
uri is a video path that I got from response of picker.
File video_file = new File(uri.getPath());
Log.d(Variables.tag + " new path", video_file.getAbsolutePath());
Functions.copyFile(video_file,
new File(Variables.gallery_resize_video));
Function calling of copyFile
public static void copyFile(File sourceFile, File destFile) throws IOException {
if (!destFile.getParentFile().exists())
destFile.getParentFile().mkdirs();
if (!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
ERROR : new path:
/storage/emulated/0/Download/STop/MP4_20210128_225711.mp4
System.err:
java.io.FileNotFoundException:
/storage/emulated/0/Download/.HidedTop/gallery_resize_video.mp4:
open failed: EACCES (Permission denied)
And app crashes at destination =
new FileOutputStream(destFile).getChannel();
By using below snippet my problem is solved.
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
the .getExternalStoragePublicDirectory() is deprecated.
Related
In my android application i'm using SQLite database.
And I need to have an option in the app to download the database file.
Because sometimes I need to view the data there , so the user will download the file and send it to me and i will browse it using SQLite browsers.
Is the doable? if yes how?
String src = "/data/data/myPackage/databases/Mydb.db";
String dest = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
copyFileOrDirectory(src , dest);
public static void copyFileOrDirectory(String srcDir, String dstDir) {
try {
File src = new File(srcDir);
File dst = new File(dstDir, src.getName());
copyFile(src, dst);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void copyFile(File sourceFile, File destFile) throws IOException {
if (!destFile.getParentFile().exists())
destFile.getParentFile().mkdirs();
if (!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
Usually, the SQLite database is available in the /data/data/your.applications.package/databases/database.db path.
So, you could use that path; however, I suggest that you get the Database Path in the following way:
File dbFile = getDatabasePath("dbname");
String dbPath = dbFile.getPath();
Then, you can copy the database from this folder into the folder that you desire.
Copying the database to the Downloads could simulate the "download" of the SQLite database.
My application gets a shared image from gallery using
Uri imageUri = (Uri) getIntent().getExtras().get(Intent.EXTRA_STREAM);
I want to be able to duplicate the file(new name) in the same location of the original file.
i am able to do this when the file is located in the internal storage, like this:
String filePath = getRealPathFromURI(this, imageUri);
String filePathNew = filePath;
int index = filePathNew.lastIndexOf('.');
filePathNew = filePathNew.substring(0, index) + "_" + System.currentTimeMillis() + filePathNew.substring(index);
File fOrig = new File(filePath);
File f = new File(filePathNew);
try {
copy(fOrig,f);
return true;
} catch (IOException e) {
MyLogger.log(ShareActivity.this, MyLogger.ERROR, e + "|||" + MyLogger.getStackTrace(e));
e.printStackTrace();
}
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception ex) {
MyLogger.log(context, MyLogger.ERROR, "Error getting Real path from URI" + ex + "|||" + MyLogger.getStackTrace(ex));
ex.printStackTrace();
return "NaN";
} finally {
if (cursor != null) {
cursor.close();
}
}
}
when the shared image is from the sd card. i get an exception
java.io.IOException: open failed: EACCES (Permission denied)
java.io.IOException: open failed: EACCES (Permission denied)
at java.io.File.createNewFile(File.java:942)
URI path from EXTRA_STREAM:
/external/images/media/37713
URI Real Path:
/storage/0709-9CE1/raz test/raz.jpg
AndroidManifest permissions:
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
MANAGE_DOCUMENTS
INTERNET
I am testing on Galaxy S7 with android 6.0.1 but the issue was raised from other users also
What am i missing?
It is weird that your code doesn't contain Android permission and you'll using android 6.x, based on the error you need to add to get permission to write on external storage before you save your file.
you need to add something like this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RESULT);}
else {
//your treatment
}
and check permission is needed to any operation that you'll do which is mentioned as permission on manifest.xml
Here are things I have done:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and
public void createMyFolder(){
File directory = new File(Environment.getExternalStorageDirectory().getPath() + "/myfolder/");
directory.mkdir(); //I had also tried mkdirs()
File file= new File(Environment.getExternalStorageDirectory().getPath() + "/t1.dat");
try {
file.createNewFile();
} catch (IOException e) {}
}
I tested 3 devices and one of them threw exception:
java.io.IOException: Cannot create dir /mnt/sdcard/myfolder
t1.dat was created successfully in /mnt/sdcard/ but myfolder was not.
The device is Xperia Ion with Android version 4.0.4. What's wrong about it and how can I fix it?
Edit: I had tried to create folders by some applications, like File Manager.
And they also failed to create although the sdcard is writable and readable.
I think my phone has some "protections" which do not allow me to create folders in sd card.
But it's funny that my phone allows me to create files instead.
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Replace Environment.getExternalStorageDirectory() with directory and also "/myfolder" will be "/myfolder"
public void createMyFolder(){
File directory = new File(Environment.getExternalStorageDirectory().getPath() + "/myfolder");
directory.mkdir(); //I had also tried mkdirs()
File file= new File(directory.getPath() + "/t1.dat");
try {
file.createNewFile();
} catch (IOException e) {}
}
Here is the problem. I got an app that download audio files to the phone then play it back. All works without problem. But the little problem is - the customer wants to have something that play straight away when the other files are being download.
So I put an short audio in the www/files/ folder. That works without any issue with iOS. I just reference it (from media player) as
document.addEventListener('deviceready' , function()
{
var media = new Media('files/default.m4a' , function()
{
// this success call back never works!
});
setTimeout(function()
{
media.play();
},100);
});
Now the problem is Android. Got a FileError.NOT_FOUND_ERR error. Looking at LogCat (From Android studio)
The path become
/mnt/sdcard/files/default.m4a
It seems that Android couldn't handle a relative path like iOS (strange enough all the images or template are relative path in the js app. And they all work fine).
Been searching up and down a solution how do I copy just that one audio file to the sd card. no luck so far. The problem is I couldn't correctly find the absolute path to the original file. There are lots of example out there which is total BS. They hardcoded the path in! Android can be anything, in the emulator is /mnt/sdcard/ on my test device turns into /external/sdcard0
And that just from (java):
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
I seen tons and tons of people got the same problem. But the solution out there are pretty out date. Or not really solve the first problem (which is finding out where is the original file in the first place). There must be one problem many people face right?
Thanks in advance.
P.S. I also try this
this.getClass().getPackage().getName();
call from inside the onCreate method. That only got me partial but not the absolute path.
UPDATE
Here is the complete working code (for PhoneGap 3.1)
package YOUR_PACKAGE_NAME;
import android.os.Bundle;
import org.apache.cordova.*;
/* for the other two plugins */
import java.io.*;
import android.os.Environment;
import android.util.Log;
import android.content.res.AssetManager;
public class YourAppName extends CordovaActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
this.CopyAssets();
super.loadUrl(Config.getStartUrl());
}
private void CopyAssets() {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(FILE_YOU_WANT_TO_COPY_IN_WWW);
out = new FileOutputStream(Environment.getExternalStorageDirectory()
.toString()
+ WHERE_YOU_WANT_TO_PUT_IT_PLUS_NAME);
this.copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
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);
}
}
}
Try this :
public class testsample extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set by <content src="index.html" /> in config.xml
CopyAssets();
super.setIntegerProperty("loadUrlTimeoutValue", 6000);
super.loadUrl(Config.getStartUrl());
}
private void CopyAssets() {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("www/img/logo.png"); // if files resides
// inside the "Files"
// directory itself
// "www/img/logo.png" is path of assets/www folder
out = new FileOutputStream(Environment
.getExternalStorageDirectory().toString()
+ "/"
+ "logo.png");
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
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);
}
}
}
Do't Forget to Add Permission on AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
A cleaner option is to install the org.apache.cordova.file-transfer plugin and transfer the file from "file:///android_asset/www/song.mp3" to /YourApp/song.mp3
cordova plugin add org.apache.cordova.file#1.1.0
cordova plugin add org.apache.cordova.file-transfer
And then:
// Assumes variable fileURL contains a valid URL to a path on the device,
// for example, cdvfile://localhost/persistent/path/to/downloads/
var fileTransfer = new FileTransfer();
var uri = encodeURI("http://some.server.com/download.php");
fileTransfer.download(
uri,
fileURL,
function(entry) {
console.log("download complete: " + entry.toURL());
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
false,
{
//headers: {
// "Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
//}
}
);
More info here:
https://github.com/apache/cordova-plugin-file-transfer/blob/master/doc/index.md
This way you only wave to worry about your javascript
i have been trying to get a screenshot lately but every thing in vain the folders are created in android emulator with api level 8. i have mentioned the code below.
In the this code Method takeScreenShot() is supposed to create a directory and store the image while executing as android junit testcase i get result as 100% but not the folders are not Created and screen shot is not stored. should i root my phone to use its sd card ?
public class NewRobotiumTest extends ActivityInstrumentationTestCase2 {
......
......
// actual testcase
public void testRecorded() throws Exception {
solo.waitForActivity("com.botskool.DialogBox.DialogBox",
ACTIVITY_WAIT_MILLIS);
solo.clickOnButton("Show Alert");
solo.clickOnButton("Ok");
solo.clickOnButton("Show Yes/No");
takeScreenShot(solo.getViews().get(0), "testRecorded_1316975601089");
solo.sleep(2000);
solo.clickOnButton("Yes");
solo.clickOnButton("Show List");
solo.clickOnScreen(118f, 563f);
}
/**
* I have added this to the android-manifest.xml file
*
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
*
*/
public void takeScreenShot(final View view, final String name)
throws Exception {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap b = view.getDrawingCache();
FileOutputStream fos = null;
try {
final String path = Environment.getExternalStorageDirectory()+ "/test-screenshots/";
File dir = new File("/mnt/sdcard/test-screenshots");
if(!dir.mkdirs()){
System.out.println("Creaet sd card failed");
}
if (!dir.exists()) {
System.out.println(path);
dir.mkdirs();
}
fos = new FileOutputStream(path + name + ".jpg");
if (fos != null) {
b.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.close();
}
} catch (IOException e) {
}
}
});
}
}
You need add permission to write to the SD Card in the main application. Not the JUnit test project!
Add this to the project manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>