this question has been asked before(not specifically like this) but there hasn't been an All Exclusive answer to it yet. so we are trying to find the best solution here. i'm developing an app and in my app i hide a directory named myPic by moving it's files to a directory called .myPic. when i hide my pictures it's thumbnails are still in gallery. i find 3 solution to this:
first solution:
using ACTION_MEDIA_MOUNTED broad cast like this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
the problem with this code is that it takes hug resources and most importantly it is blocked since android 4.4. so using this method is not rational for adding 10 pictures to gallery. so it is not an All exclusive method. also using ACTION_MEDIA_SCANNER_SCAN_FILE doesn't work on android 4.4 either
second solution:
using MediaScannerConnection. so i created a for loop and pass the old address of every file that i hide. this is my MediaScannerConnection function:
private void scanFile(File file) {
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(this,new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
the thing about MediaScannerConnection is that it only effect if the file exist. so lets say i have a picture called 1.jpg in myPic directory. using this class i can add 1.jpg to my gallery immediately but when i move 1.jpg to .myPic directory and i scan the old path of 1.jpg nothing happen. logcat says that this file doen't exsit. so MediaScannerConnection only add files to gallery. what if i pass the new path of 1.jpg to MediaScannerConnection? well it adds 1.jpg from .myPic directory to gallery and that is exactly not what i want. so again not an All Exclusive method
third solution:
using getContentResolver(). so for deleting thumbnails this method may be the ultimate solution. so i write the blow code. in every loop i retrieve the path of image and pass it to getContentResolver().delete(Uri.parse(path),null,null). here is the code:
File myPic = new File(Environment.getExternalStorageDirectory()+"/myPic");
File myPicHide = new File(Environment.getExternalStorageDirectory()+"/.myPic");
if (!(myPicHide.exists()) & !(myPicHide.isDirectory())) {
myPicHide.mkdirs();
};
if (myPic.isDirectory()) {
String[] childeren = myPic.list();
if (childeren.length > 0) {
for (int i = 0; i < childeren.length; i++) {
String fileName = childeren[i];
File from = new File(Environment.getExternalStorageDirectory()+"/myPic"+fileName);
File to = new File(Environment.getExternalStorageDirectory()+"/.myPic"+fileName);
from.renameTo(to);
try {
String path = from.toString();
getContentResolver().delete(Uri.parse(path),null,null);
} catch(Exception e) {
Log.d("Rename", "Error happened");
}
}
}
} else {
Toast.makeText(getApplicationContext(), "myPic directory not found", Toast.LENGTH_LONG).show();
}
but it's not working either and thumbnails of my files are still showed in galley. so am i using getContentResolver() in wrong way?? this might be the all Exclusive method for the situation where deleted files thumbnails show up in gallery. i have my files path and i need to only delete it from media store content provider.
update:
so turns out that using Uri.parse(path) in the third solution is wrong. image Uri is started with content:// and it can be retrieved by MediaScannerConnection. so i created a Uri called imageInGalleryUri and assign null value to it. using my scanFile function i changed it's value from time to time and pass it's value to getContentResolver(). here is the code:
boolean whereIsMediaState = true;
Uri imageInGalleryUri = null;
File myPic = new File(Environment.getExternalStorageDirectory()+"/myPic");
File myPicHide = new File(Environment.getExternalStorageDirectory()+"/.myPic");
if (!(myPicHide.exists()) & !(myPicHide.isDirectory())) {
myPicHide.mkdirs();
};
if (myPic.isDirectory()) {
String[] childeren = myPic.list();
if (childeren.length > 0) {
for (int i = 0; i < childeren.length; i++) {
String fileName = childeren[i];
File from = new File(Environment.getExternalStorageDirectory()+"/myPic"+fileName);
scanFile(from);
File to = new File(Environment.getExternalStorageDirectory()+"/.myPic"+fileName);
from.renameTo(to);
if (to.isFile()){
try {
getContentResolver().delete(imageInGalleryUri,null,null);}
catch(Exception e) {
Log.d("Rename", "Error happened");
}
}
}
} else {
Toast.makeText(getApplicationContext(), "myPic directory not found", Toast.LENGTH_LONG).show();
}
private void scanFile(File file) {
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(this,new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
imageInGalleryUri = uri;
}
});
}
i tried the code but it only detect the first image and delete it from the gallery but does not effect the other images. i can't figure out why. any idea?
thank you for your help in advance
. before folder just make it invisible. But there is way to say don't use this folder at all to gallery.
Please try to put empty file called ".nomedia" file into your folder.
Related
I`m making an app to test the Opencv haarcascades and it seems like my app does not see the .xml files. My permission include:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
My code for collecting the file names and path is:
public ArrayList<String []> getLongAndShortFileHandles(String root_dir) {
ArrayList<String[]> ret = new ArrayList<>();
String path = Environment.getExternalStorageDirectory().toString()+"/"+root_dir;
File directory = new File(path);
File[] files = directory.listFiles();
Log.e(TAG, "getLongAndShortFileHandles: Has dir "+path+", with "+((files==null) ? "null" : files.length) + " number of files");
for (int i = 0; i < Objects.requireNonNull(files).length; i++)
{
Log.e(TAG, "getLongAndShortFileHandles: HAS FILE "+files[i].getName());
String [] temp = new String [] {files[i].getAbsolutePath(),files[i].getName()};
ret.add(temp);
}
return ret;
}
The debug shows that no files are present when I call this function to populate my RecycleView subclass like so:
this.cascade_selector = (RecyclerView) findViewById(R.id.cascade_view);
this.cascade_selector.setAdapter(new FileAdaptah(getLongAndShortFileHandles("cascade_app/cascades"),this, CASCADE));
this.xml_ano_selector = (RecyclerView) findViewById(R.id.annotation_view);
this.xml_ano_selector.setAdapter(new FileAdaptah(getLongAndShortFileHandles("cascade_app/annotations"),this, ANNOTATION_XML));
The result in the app does show the output for second call but not for the first one.
If the first one is replaced with any other folder like DCIM, or Music it shows the files.
However if I add .xml file into any directory it will not be shown.
EDIT:
I was playing around with different directories and files and determined that the problem goes further then just .xml it seem to be all the ascii encoded text file formats I could think of. All binaries like .jpg, .wav, .mp4, .bin and etc. are found in when put in same directory.
EDIT (2):
So I`ve established that if I rename any of the text file extensions into any binary one (e.g. 50.xml -> 50.jpg they are detected by the script.
This prompted me to try different filename filters, but they didn't yield any success.
I`ve also tried to use Directory Stream instead but to no avail:
#RequiresApi(api = Build.VERSION_CODES.O)
public ArrayList<String[]> getFiles(String suffix, String root_dir){
ArrayList<String[]> ret = new ArrayList<String[]>();
try {
root_dir = Environment.getExternalStorageDirectory().toString() + "/" + root_dir;
Path dirName = Paths.get(root_dir);
DirectoryStream<Path> paths = Files.newDirectoryStream(dirName, "*.pdf");
paths.forEach(path -> {
Log.e(TAG, "getFiles: HAS FILE : "+path.toString());
if (path.endsWith(suffix)) {
String sPath = path.toString();
String[] splitted = sPath.split(File.separator);
ret.add(new String[]{sPath, splitted[splitted.length - 1]});
}
});
} catch (IOException exception) {
exception.printStackTrace();
}
return ret;
}
I`ve started to suspect it might be a bug, so I provide my environment information: My android studio is version 4.1.2 and my target SDK is 30, while my minimum accepted is 19. My test device is a physical Galaxy A40 with android 11.
EDIT (3):
So I've noticed that the second snippet for getFiles has leftover glob expression from the point I've copied the original snippet. Out of interest I've modified and removed it but in either case nothing changed.
EDIT (4):
So I've tried to access file directly with the following code:
this.test = (Button) findViewById(R.id.select_to_test);
this.test.setOnClickListener(v -> {
String path = Environment.getExternalStorageDirectory().toString()+"/cascade_app/cascades/50.xml";
Intent intent = new Intent(v.getContext(),CheckCascade.class);
intent.putExtra("fh",path);
File debugFile = new File(path);
Toast.makeText(this, "File "+path+" does "+((debugFile.exists())? "exist":"not exist"), Toast.LENGTH_SHORT).show();
startActivity(intent);
});
}
and it seem to detect it no problem.
So after some time I was helped by a kind person who suggested to check if my app needs
this permission. This solved the problem! I hope this can help people who will have same issue.
I tried to move a photo taken by the camera to a folder named "raspberrypi" I created. But the .renameTo() keeps returning false. I cannot find the reason. To clarify, the photos I am trying to move are taken by the camera, so they aren't in any folder to begin with.
imagesEncodedList is an ArrayList of File path Strings.
boolean bool=false;
for(int i=0; i<imagesEncodedList.size();i++){
File from;
File to=null;
try{
from=new File(imagesEncodedList.get(i));
String dateString=new SimpleDateFormat("MM_dd_yyyy_HH:mm:ss").format(Calendar.getInstance().getTime());
to=new File(getPublicDir(),"SideBySide4_ImportedPhoto"+i+"_"+dateString+".jpg");
bool=from.renameTo(to);
}catch(Exception e){
e.printStackTrace();
}
MediaScannerConnection.scanFile(this,
new String[]{to.getPath()},
null,
null);
}
Toast.makeText(this, "Success?: "+bool, Toast.LENGTH_LONG)
.show();
Here is my getPublicDir() function implementation:
public File getPublicDir() {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "raspberry");
if (!file.mkdirs()) {
Log.e("PUBLIC DIRECTORY", "Directory not created");
}
return file;
}
renameTo only works if source and target are on the same disk partition. If they're not, you'll have to copy the source file and delete it afterwards.
context.getFilesDir() is on a different partition (/data) than Environment.getExternalStoragePublicDirectory (typically accessible under /sdcard).
I'm new to Android Studio 3.0, emulating on a Nexus 4, Marshmallow. I'm trying to build simple "Save File" and "Load File" parts of my app. Here's the "Save File" part:
String filename = "myFile01"; // Then "myFile02", "myFile03", etc...
String userData = "Some useful data here...";
try {
// Adapted from: https://www.youtube.com/watch?v=_15mKw--RG0
FileOutputStream fileOutputStream = openFileOutput(filename, MODE_PRIVATE); // creates a file with given filename
fileOutputStream.write(userData.getBytes()); // puts userData into the file
fileOutputStream.close();
Toast.makeText(getApplicationContext(), "File saved!", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The above code will be called again and again as the user creates and saves additional files. Later, the user may want to view all the saved files and load one. I'll have a ListView displaying all the files... but I need help reading the current directory to get that list.
I thought I read somewhere that in Android, there's one flat directory for your app to save and retrieve files. So I was hoping if I saved a bunch of files and then called a read() method, all my saved files would simply be in the default directory, no need to search. That seems to be a bad assumption; here's why:
Here's my code looking in the default directory and listing all the files found within there. First, I need the path of said default directory:
// Get current directory adapted from: https://stackoverflow.com/questions/5527764/get-application-directory
String packName, currDir;
PackageManager m = getPackageManager();
packName = getPackageName();
PackageInfo p = null;
try {
p = m.getPackageInfo(packName, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
currDir = p.applicationInfo.dataDir;
And then I open "currDir," and store the names of all the local files in an array:
// get list of files adapted from: https://stackoverflow.com/questions/9317483/showing-a-list-of-files-in-a-listview#9317583
File dir = new File(currDir);
File[] filelist = dir.listFiles();
String[] fileArr = new String[filelist.length];
for (int i = 0; i < fileArr.length; i++) {
fileArr[i] = filelist[i].getName();
}
The plan from here is to load the "fileArr" into a ListView and go from there. But when I step through the debugger, I see this as the contents of "fileArr":
"cache"
"code_cache"
"files"
This is true no matter how many files I've saved previously.
BTW, in the debugger, the assignments for packName and currDir look 100% correct:
packName = com.mydomain.myapp
currDir = /data/user/0/com.mydomain.myapp
So... I'm kinda assuming that my saved files are actually here:
/data/user/0/com.mydomain.myapp/files
And therefore, I should append this to my "get current directory" code:
// Get current directory adapted from: https://stackoverflow.com/questions/5527764/get-application-directory
String packName, currDir;
...everything from before...
currDir = p.applicationInfo.dataDir+"/files"; // <---- appending "+"/files"
Or am I way off? Any advice will be appreciated, thanks!
First of all, if you want to save your files in the app's directory, then you should call create a directory,
File directoryDefault = new File(Environment.DIRECTORY_DOCUMENTS, "YOUR_FOLDER_NAME");
if (!directoryDefault.exists()) {
directoryDefault.mkdir();
}
Then you have to save whatever files you have to save in the above mentioned default directory. Afterwards, when you want to list all the files available in that directory, you should call,
private ArrayList<String> fileNames() {
ArrayList<String> namesArray = new ArrayList<>();
File[] arrayFiles = directoryDefault.listFiles();
for (File file : arrayFiles) {
namesArray.add(file.getName());
}
return namesArray;
}
I am making an app on Android Studio with tesseract OCR. I made a code which should recognize text on images taken by phone camera. Problem: tesseract function getUTF8Text() gives no result AT ALL (null, despite picture being with text). Program does not give any errors.
I wondered about possible issues: 1. Maybe I integrated tesseract into my project not properly? (Compilator does not show any issues when using tesseract classes in code) 2. Maybe problem in code? (bad traineddata path??).
Main class:
Code:
private TessOCR Tess;
//after taking picture I call:
PictureCallback pictureCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
String result = Tess.getOCRResult(bitmap);
if (result != null) Log.i(TAG, result);
else Log.i(TAG, "NO RESULT");
}
};
TessOCR class for tesseract traineddata file finding or adding and text recognition (Constructor is only for finding traineddata file):
public class TessOCR {
public static final String PACKAGE_NAME = "com.example.dainius.ocr";
public static final String DATA_PATH = Environment
.getExternalStorageDirectory().toString() + "/AndroidOCR/";
public static final String lang = "eng";
private static final String TAG = "OCR";
private TessBaseAPI mTess;
public TessOCR(AssetManager assetManager) {
mTess = new TessBaseAPI();
String[] paths = new String[] { DATA_PATH, DATA_PATH + "tessdata/" };
for (String path : paths) {
File dir = new File(path);
if (!dir.exists()) {
if (!dir.mkdirs()) {
Log.v(TAG, "ERROR: Creation of directory " + path + " on sdcard failed");
return;
} else {
Log.v(TAG, "Created directory " + path + " on sdcard");
}
}
}
if (!(new File(DATA_PATH + "tessdata/" + lang + ".traineddata")).exists()) {
try {
InputStream in = assetManager.open("tessdata/" + lang + ".traineddata");
OutputStream out = new FileOutputStream(DATA_PATH
+ "tessdata/" + lang + ".traineddata");
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
Log.v(TAG, "Copied " + lang + " traineddata");
} catch (IOException e) {
Log.e(TAG, "Was unable to copy " + lang + " traineddata " + e.toString());
}
}
mTess.setDebug(true);
mTess.init(DATA_PATH, lang);
}
public String getOCRResult(Bitmap bitmap) {
mTess.setImage(bitmap);
String result = mTess.getUTF8Text();
return result;
}
public void onDestroy() {
if (mTess != null)
mTess.end();
}
If this problem is caused by bad tesseract integration, please post a proper tutorial about how to integrate it, because every tutorial on the internet is different from each other, it's hard to understand how to properly do it.
I've worked with Tesseract (tess4j). Have you tried using an image with very clear text and completely monochrome/grayscale? I've found that when I'm trying to get Tesseract to read my images it's much more useful to spend time manipulating the image trying to make it easier for Tesseract.
If you still aren't able to get it to produce output and it isn't showing any errors, I'd go here and restart the Tesseract setup with the tutorial and follow all of their tips. It shouldn't be too difficult, the .dll's are extracted and loaded automatically. Just make sure your tessdata folder is in the correct spot (root directory) and you have all the .jar's (I think there's only 4 that you need, not all of them, but check the tutorial on tess4j.sourceforge.com) as compile-time libraries.
Taken from their website: "Images intended for OCR should have at least 200 DPI in resolution, typically 300 DPI, 1 bpp (bit per pixel) monochome or 8 bpp grayscale uncompressed TIFF or PNG format." To be honest, I haven't had much luck with Tesseract besides their PDF tools to scan easy-to-read high-resolution documents.
I didn't get it to work the first time either, for what it's worth.
The cause of my problem was that I did not as permission to write external storage. If anyone will try to apply this method to extract file from assets folder (got this method from this github project), make sure you add permission to write external storage code line to your manifest (AndroidManifest.xml file):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
This is my function for converting blob to mp3:
private void convertByyeToMP3(byte[] bytearray,String trackName) {
try {
ContextWrapper c = new ContextWrapper(getApplicationContext());
File directory = new File(c.getFilesDir().getAbsolutePath()
+ "/Music");
if (!directory.exists()){
directory.mkdir();
}
File tempMp3 = File.createTempFile(trackName, ".mp3",
directory);
FileOutputStream fos = new FileOutputStream(tempMp3);
fos.write(bytearray);
fos.close();
Log.d("Byte array to mp3 conversion: ", "successfull");
} catch (Exception ex) {
Log.d("In convertToByteToMp3 Function:", ex.toString());
}
}
When I execute this function ,I can see the created mp3 files in my app folder but when I try to play them Using my own code or using ES File Explorer, they both can't play it.
This is the function I use play my music:
private MediaPlayer mp = new MediaPlayer();
private void playSong(String songPath) {
try {
mp.reset();
mp.setDataSource(songPath);
mp.prepare();
mp.start();
} catch (IOException e) {
Log.v(getString(R.string.app_name), e.getMessage());
}
}
And I use this sample code to play the track:
ContextWrapper c = new ContextWrapper(getApplicationContext());
File directory = new File(c.getFilesDir().getAbsolutePath() + "/Music");
playSong(directory.getPath() + File.separator + "kurchina");
This is where I read database and send the blob:
cursor = mDbHelper.GetTables();
byte[] blob = null;
DATAS data = new DATAS();
while (cursor.moveToNext()) {
blob = cursor.getBlob(cursor.getColumnIndex("data"));
if (blob != null) {convertByyeToMP3(blob,data_MusicName);}
db.addDATAS(data);
}
FYIs:
-Read and Write permissions added to manifest.
-Path and filename are check and they exist
-blob byte is not corrupted
There are all sorts of things that might have gone wrong, either in the code that you have shown us or elsewhere. So you need to do your own troubleshooting. Methodically.
Figure out if the problem is with the song file you have extracted or the way you are playing it. For example, try to play the extracted file using a free-standing mp3 player utility.
Assuming that the problem is the extracted file, the next thing is to figure out if the file is the same as the one that you originally inserted into the database. Compare the file sizes and the checksums using the relevant external applications.
and so on.
Found the problem.
It didn't play because the music files were stored in my app folder which is only accessible using a rooted device.
When I copied the music to my sdcard they played well, but in my app folder using rooted nexus 7 I couldn't play it even with an mp3-player app.