I am a newbie to android app making and I am still a beginner with a little knowledge . I have been trying to make an android app that works like a gallery , but it only displays images under a specific folder. For the UI , I am starting with only a GridView (or TwoWayGridView which is derived from the latter) , and have been trying to let this GridView take its contents from this folder .
I have made this folder and copied an image to it for testing and failed. No image was displayed .Plus I am not very familiar with Cursors and ListAdapters . Somethings that I'm sure that are correct are permissions , manifest , and layout of the activity.Moreover , I believe my problem is around URIs . Please check my code below :
Some namings:
Uri contentUri;
Cursor mImageCursor;
TwoWayGridView mImageGrid;
ListAdapter mAdapter;
String sdCard = Environment.getExternalStorageDirectory().getAbsolutePath();
onCreate method :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
File motherDirectory = new File(sdCard+"/Favory");
if(!motherDirectory.exists()){
motherDirectory.mkdir();
}
MediaScannerConnection.scanFile(this, new String[]{motherDirectory.getAbsolutePath()} ,null, new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
// TODO Auto-generated method stub
contentUri = uri ;
initGrid(uri);
}
});
}
initGrid(Uri) method :
private void initGrid(Uri folderUri) {
mImageCursor = this.getContentResolver().query(folderUri,
ImageThumbnailAdapter.IMAGE_PROJECTION, null, null,
MediaStore.Images.ImageColumns.DISPLAY_NAME);
mImageGrid = (TwoWayGridView) findViewById(R.id.gridview);
mAdapter = new ImageThumbnailAdapter(this, mImageCursor);
mImageGrid.setAdapter(mAdapter);
mImageGrid.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(TwoWayAdapterView<?> parent, View v, int position, long id) {
Log.i(TAG, "showing image: " + mImageCursor.getString(ImageThumbnailAdapter.IMAGE_NAME_COLUMN));
Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
}
Thanks for your help , and please if there is an easier alternative way of doing this tell me, I care for the results more than the methods now . If you need anything or any more information please tell me in the comments below . Thanks again !
To Read the Files of a folder you can use this function ( from this post ):
String directoryName = Environment.getExternalStorageDirectory().toString()+"/YourFolder/";
public ArrayList<File> listf(String directoryName, ArrayList<File> files) {
File directory = new File(directoryName);
// get all the files from a directory
File[] fList = directory.listFiles();
for (File file : fList) {
Log.e("path : "," "+file);
if (file.isFile()) {
files.add(file);
} else if (file.isDirectory()) {
listf(file.getAbsolutePath(), files);
}
}
return files;
}
Then you should load this list of files to your GridView Adapter, i suggest you use Universal Image Loader
You just give your file path and Adapter ImageVIew at that position
loadImageUtil.loadBitmapToImageView(imageView, youArrayList.get(position));
For more informations how to use this library you can see examples, there is an example with grid view gridView
Related
I'm trying to build a Gallery-like app which will perform the following functions on External storage:
List all the folder that has images inside it
List all the images that available to the public (will not probe the files inside Android/data)
So far I can list all the images, and folders that have images. However, I later find that these images and folders are not the newest ones: they are not getting refreshed after I put some pictures (say I simply do some screenshots or download some pictures).
And new pictures are not appear even after I call MediaScannerConnection.scanFile.
Except the MediaScannerConnection, I've also tried the expensive Intent.ACTION_MEDIA_SCANNER_SCAN_FILE method with the specified folders, and no luck.
I've browsing on StackOverflow as well as various of sources with people discussing this issue, but none of them can offer a working method.
Sources I've checked/tried:
http://droidyue.com/blog/2014/01/19/scan-media-files-in-android/
Trigger mediascanner on specific path (folder), how to?
Code:
How I list all the images:
private String[] projectionThumbnail = new String[]{MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.IMAGE_ID, MediaStore.Images.Thumbnails.DATA};
private Uri uriThumbnail = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI;
private String[] projectionFull = new String[]{MediaStore.Images.Media._ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.DATA};
private Uri uriFull = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ALL_IMAGES:
return new CursorLoader(getActivity(), uriThumbnail, projectionThumbnail, null, null, MediaStore.Images.Thumbnails._ID + " DESC");
default:
return null;
}
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
case LOADER_ALL_IMAGES:
adapter.changeCursor(cursor);
break;
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.changeCursor(null);
}
// And here's how I init the CursorLoader
LoaderManager lm = getActivity().getLoaderManager();
lm.initLoader(LOADER_ALL_IMAGES, null, this);
Here's how I start scanning the images, I intend to scan the whole External storage, but for now, I'll just scan DCIM, PICTURES and DOWNLOADS just for experiment
File dcim = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File pictures = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
MediaScannerConnection.scanFile(this,
new String[]{dcim.getAbsolutePath(), pictures.getAbsolutePath(), downloads.getAbsolutePath()}, new String[]{"image/*", "image/*", "image/*"},
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
Question:
I did my test on Stock 5.0.2 and 4.4, same result on both of them.
Am I doing anything wrong?
Why does the MediaScanner not working?
Note:
Interestingly, if I open Instagram and open "select gallery" from there. The gallery content is getting refreshed. So it means Instagram is doing the "gallery refreshing" very well so that my app can also receive the newest gallery content, how do they do that?
Am am trying to work with this tutorial here which loads every image on the device into a grid view, but im not sure how to modify it to just display images from one particular directory in external storage.
Get the folder content with folder.listFiles() and create an Uri from every entry.
String folderName="Photos";
ArrayList<Uri> images = new ArrayList<Uri>();
File folder = new File(Environment.getExternalStorageDirectory() + File.separator
+ folderName);
File[] files = folder.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String filename) {
return filename.endsWith(".jpg") || filename.endsWith(".png");
}
});
for (File file : files) {
images.add(Uri.parse(file.getAbsolutePath()));
}
Then you could use the array list with uris to pass it to the adapter.
im trying to make folder browser for my app, but i have error that throws me out of browser activity. When activity is started , it shows root folder with all folders in it, then I can click on one of the folders, and it opens and shows all folders in it, and after that, if i click on something, ive got error,also variable File[] filenames is null after last click. So method getFileFromList(String path) works fine 2 times and crashes on 3rd. And i dont have any errors in console. Whats wrong with my code?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fflist);
pathtext = (TextView) findViewById(R.id.pathtext);
getFileFromList("/");
registerForContextMenu(getListView());
}
protected void onListItemClick(ListView l, View v, int position, long id) {
Log.d(LOG_TAG, String.valueOf(position));
String clickedItem = neededFilenames.get(position);
getFileFromList(clickedItem);
}
public void getFileFromList(String path) {
Log.d(LOG_TAG, path);
neededFilenames = new ArrayList<String>();
File dir = new File(path);
File[] filenames = dir.listFiles();
Log.d(LOG_TAG, String.valueOf(filenames));
if (filenames != null) {
for (int i = 0; i < filenames.length; i++) {
if (filenames[i].isDirectory() && !filenames[i].isHidden() && filenames[i].canRead()) {
neededFilenames.add(filenames[i].getName());
}
}
Log.d(LOG_TAG, String.valueOf(neededFilenames));
} else Toast.makeText(this, "something wrong", Toast.LENGTH_SHORT).show();
Collections.sort(neededFilenames);
pathtext.setText("Location: /" + path);
FileFolderAdapter adapter = new FileFolderAdapter(this, neededFilenames);
setListAdapter(adapter);
}
actually i found out, that this "browser" only works in the root folder and 1 click out of it< because at the begining, when you using only items names,you have legit "path" to root- "/" , and after 1 click you will get "path" variable as - " /folder" and that still is legit path to folder, after 2 click on any folder in that first folder, you just have only that folder name "folder", without all path to root "/", so you cant make new File only out of name without having full path from root. not sure if its understandable enough, but maybe it helps someone :)
The code below can not get the video thumbnails of videos which were located in R.raw folder.
I want to use a gallery to show the thumbnails of videos. Videos were put into R.raw folder (actually I'm new to Android, so I don't really know where to put these videos, so I put them in R.raw folder). Now I want to get the thumbnails of the videos. But someone told that thumbnails can only be got from the SD card. So is it true? And what should I do next? Thanks.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Gallery gallery = (Gallery) findViewById(R.id.gallery);
final String[] videoFileList = new String[] { "R.raw.01", "R.raw.02" };
BaseAdapter adapter = new BaseAdapter() {
public int getCount() {
return videoFileList.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(Select.this);
Bitmap bmThumbnail;
bmThumbnail = ThumbnailUtils.createVideoThumbnail("android.resource://" + getPackageName() + "/"
+ videoFileList[position], Thumbnails.MINI_KIND);
System.out.println(videoFileList[position]);
imageView.setImageBitmap(bmThumbnail);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
TypedArray typedArray = obtainStyledAttributes(R.styleable.Gallery);
imageView.setBackgroundResource(typedArray.getResourceId(
R.styleable.Gallery_android_galleryItemBackground, 0));
return imageView;
}
};
gallery.setAdapter(adapter);
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(Select.this, Play.class);
intent.putExtra("image", videoFileList[position]);
startActivity(intent);
Select.this.finish();
}
public void onNothingClick(AdapterView<?> parent) {
}
});
}
On Android 5, createVideoThumbnail() always returned null when asking for the thumbnail of a video in resources. Here's what worked for me in the end:
Uri videoURI = Uri.parse("android.resource://" + getActivity().getPackageName() + "/raw/animation");
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(getActivity().getApplicationContext(), videoURI);
Bitmap thumb = retriever.getFrameAtTime(10, MediaMetadataRetriever.OPTION_PREVIOUS_SYNC);
videoView.setBackground(new BitmapDrawable(getResources(), thumb));
Have you looked at, createVideoThumbnail() from ThumbnailUtils Class?
Actually, Your video files are in resource/raw directory so you have to create Thumbnails for it.
If your video files are in External Storage then Android Media Store itself creates for you. And you can get it by MediaStore.Video.Thumbnails Class.
Video on res/raw folder of your application isn't managed by Android Media Content Provider, so you cannot obtain their thumbnail from it.
Alternatively, you can try to save them as normal file in your SD and, then, ask to media provider for thumbnail or create it directly via ThumbnailUtils.createVideoThumbnail class (only Android 2.2 or above)
I am trying to save an image from my application to the default gallery of my phone. The code below works perfectly if I have a SD card on the phone. The image saved appears in the phone's gallery and everything, as expected:
private Uri saveMediaEntry(File f, String title, String description, int orientation, Location loc) {
ContentValues v = new ContentValues();
v.put(Images.Media.TITLE, title);
v.put(Images.Media.DISPLAY_NAME, title);
v.put(Images.Media.DESCRIPTION, description);
v.put(Images.Media.ORIENTATION, orientation);
String nameFile = f.getName();
File parent = f.getParentFile() ;
String path = parent.toString().toLowerCase() ;
String nameParent = parent.getName().toLowerCase() ;
v.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
v.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, nameParent);
v.put(Images.Media.SIZE,f.length()) ;
if( nameFile.toLowerCase().contains(".png") ){
v.put(Images.Media.MIME_TYPE, "image/png");
}else if( nameFile.toLowerCase().contains(".jpg") ||
nameFile.toLowerCase().contains(".jpeg") ){
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}else{
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}
String imagePath = f.getAbsolutePath();
v.put("_data", imagePath) ;
ContentResolver c = getContentResolver() ;
Uri uriOfSucessfulySavedImage = null;
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, v);
return uriOfSucessfulySavedImage;
}
However, if I try to save the same image into the internal storage (for when the phone does not have a SD card), the image does not appear in the phone's gallery! To try to do that, I only change one line from the above code:
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, v);
The interesting thing about this, however, is that the variable uriOfSucessfulySavedImage is not null (it returns content://media/internal/images/media/x, where 'x' is a number). So, the image is being saved somewhere in the internal storage of the phone, but it is not getting displayed in the phone gallery's as when I use MediaStore.Images.Media.EXTERNAL_CONTENT_URI.
Does anybody have any clue what is going on? How can I save an image into the internal storage of the phone and have that image in the phone's gallery?
Update
I forgot one important information. The File "f" in the parameters of the method "saveMediaEntry" is coming from this other method for when the SD card is mounted (that is, for the first code):
public static File getCacheDirectory(String desiredNameOfTheDirectory){
File fileCacheDir = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ){
fileCacheDir = new File( Environment.getExternalStorageDirectory(), desiredNameOfTheDirectory );
}
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
and from the following code for when the SD card is not founded:
public static File getCacheDirectory(String desiredNameOfTheDirectory, Context context){
File fileCacheDir = null;
fileCacheDir = context.getCacheDir();
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
Another easy way to do it. Add this after saving your file.
File imageFile = ...
MediaScannerConnection.scanFile(this, new String[] { imageFile.getPath() }, new String[] { "image/jpeg" }, null);
I haven't tried this, but I believe you need to run the Media Scanner to scan the internal storage directory so that the gallery can see your newly saved image. Check this post here.
Copy Past this Function in your Activity
private void scanner(String path) {
MediaScannerConnection.scanFile(FrameActivity.this,
new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("TAG", "Finished scanning " + path);
}
});
}
And then add this Line where you save your image
scanner(imageFile.getAbsolutePath());
Try this.
Write down this line once image stored in gallery.
File file = ..... // Save file
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
}