I'm sure this is a trivial question, but I failed to find an answer.
I'm making an Android app from which I want to open the image viewer
showing several images. I know how to do this with only one image:
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
File file1 = new File("/mnt/sdcard/photos/20397a.jpg");
intent.setDataAndType(Uri.fromFile(file1), "image/jpg");
startActivity(intent);
This works perfectly. But how do I pass several images to the viewer?
Thanks!!
L.
I want to open the image viewer
There is no "the image viewer" in Android. Devices and users may have many, many different apps that are capable of viewing image/jpeg files loaded from a local file.
But how do I pass several images to the viewer?
Sorry, but there is no standard Intent to open multiple files of any sort.
Also, please do not hardcode /mnt/sdcard/ in your app. Please use the proper methods on the Environment class to determine directories on external storage.
You need to list all files you want to view in a array. Then you display one of the array and when you drag, you show the next image.
ArrayList list;
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Ansi date format
list = new ArrayList();
String path = "c:/temp/";
File dir = new File(path);
for (String dirListing : dir.list()) {
if ((dirListing.endsWith(".jpg")) ||
(dirListing.endsWith(".png")) ||
(dirListing.endsWith(".gif"))) {
try { // write all file-info to a arraylist
File f = new File(path+dirListing);
list.add(f.getCanonicalPath());
list.add(f.getName());
list.add(String.valueOf(f.length()));
String lastModified = dateFormat.format(new Date(f.lastModified()));
list.add(lastModified);
}
catch (IOException e) {
e.printStackTrace();
}
catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
Now you can read the array and display then one by one.
Do not use Hard Coded Paths.
Change this line :
File file1 = new File("/mnt/sdcard/photos/20397a.jpg");
to
File sdDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
It will locate to
/storage/emulated/0/Picture
You can remove Environment.DIRECTORY_PICTURES If you want the parent directory of your sdcard.
Since you are specifying a single file 20397a.jpg that's why you are unable to see other images.
And if you want to see other contents other than images then change 'image/jpg' to 'image/*'
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.
The android application I am working on; it has an option of audio-recording; I want it to save a new audio recorded file in internal storage of a device so that no neither user nor other applications will be able to access to those recorded audio files, unless they open my application.
My main struggle is to be able to save that audio file in internal storage: I took my time to review in my android programming books and read some questions and answers here : How to save an audio file in internal storage android and https://developer.android.com/guide/topics/data/data-storage#filesInternal and https://www.tutorialspoint.com/android/android_internal_storage.htm but unfortnately things I am getting from there are not settling my problem at all.
The codes that I am using to record are here below :
private MediaRecorder rec;
private String file_folder="/scholar/";
String
file_path=Environment.getExternalStorageDirectory().getPath();
File file= new File(file_path,file_folder);
Long date=new Date().getTime();
Date current_time = new Date(Long.valueOf(date));
rec=new MediaRecorder();
rec.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
rec.setAudioChannels(1);
rec.setAudioSamplingRate(8000);
rec.setAudioEncodingBitRate(44100);
rec.setOutputFormat(MediaRecorder.AudioEncoder.AMR_NB);
rec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
if (!file.exists()){
file.mkdirs();
}
/*the file here this one:File file= new File(file_path,file_folder);
it means the value of the outputfile is the one which will be provided by
rec.setOutputFile() method, so it will be saved as this name:
file.getAbsolutePath()+"/"+"_"+current_time+".amr"
*/
rec.setOutputFile(file.getAbsolutePath()+"/"+"_"+current_time+".amr");
try {
rec.prepare();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(Recording_Service.this,"Sorry! file creation failed!",Toast.LENGTH_SHORT).show();
return;
}
rec.start();
rec.stop();
rec.reset();
Unfortunately what I am doing there, is saving my file on external storage, it means after recording, the file is visible to everyone in a device file explorer, they can even delete the file.
So! Please, I need your help guys, if any help, I will appreciate it. Thanks!
I had found the answer of this question, I used getFilesDir();
private MediaRecorder rec;
String file_path=getApplicationContext().getFilesDir().getPath();
File file= new File(file_path);
Long date=new Date().getTime();
Date current_time = new Date(Long.valueOf(date));
rec=new MediaRecorder();
rec.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
rec.setAudioChannels(1);
rec.setAudioSamplingRate(8000);
rec.setAudioEncodingBitRate(44100);
rec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
rec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
if (!file.exists()){
file.mkdirs();
}
String file_name=file+"/"+current_time+".3gp";
rec.setOutputFile(file_name);
try {
rec.prepare();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(Recording_Service.this,"Sorry! file creation failed!"+e.getMessage(),Toast.LENGTH_SHORT).show();
return;
}
rec.start();
rec.stop();
rec.reset();
Thanks for everyone who tried to help me for the answer. Let's continue to enjoy coding to make our world more sweet pleasant and enjoyable.
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 working on a program that looks at an mp3 file and checks if it has it's ID3 data. If some data is missing it will query EchoNest (music database) for more data.
My problems is that when I update the ID3 tags Windows Explorer doesn't seem to recognize it (ie when the files are in the "Details" view the Artist, Title, Album columns are blank).
When I run my program a second time on the file my program finds the metadata just like it would find in a file that has all of it's data at first.
I am using the ID3 tag library found here:
http://javamusictag.sourceforge.net/
Is there something I am missing?
public void writeData(boolean pForce)
{
if (mIsUpdated || pForce)
{
try
{
File file = new File(mPath);
RandomAccessFile destFile = new RandomAccessFile(file, "rw");
ID3v1 tag = new ID3v1();
tag.setAlbum(mAlbum);
tag.setArtist(mArtist);
tag.setTitle(mTitle);
tag.write(destFile);
}
catch (FileNotFoundException ex)
{
System.out.println("No File Found At " + mPath);
}
catch (IOException ex)
{
System.out.println("Error when writting to file: " + mPath);
}
}
}
Just as a not I know that there are programs out there that do this same thing but I'm looking to add this as a function of my program. It's not so much about the functionality as it is about the learning how to make a program that does this.
Have you tried using ID3v2 tags, because when I was reading tags (with that library) from music files in windows, only v2 seemed to work. Hope it helps
EDIT:
If that doesn't work, I found this on another question using mp3agic: (the image stuff is to do with album artwork)
Mp3File song = new Mp3File(filename);
if (song.hasId3v2Tag()){
ID3v2 id3v2tag = song.getId3v2Tag();
byte[] imageData = id3v2tag.getAlbumImage();
//converting the bytes to an image
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageData));
}
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.