I am recording the screen and saving it in a Particular folder and then after saving it i have a button to show all the videos in that folder.
newly saved videos are not updating but if i go in file-explorer and open that folder there the video is showing and then if i again see all videos of that folder in my app ,now the video appears there too .How to make that video appear first time only i.e after saving the video if i click (view all video) button the video should be there.
My code for fetching all videos from folder
private void init()
{
recyclerView = findViewById(R.id.recycler_view);
swipeRefreshLayout = findViewById(R.id.pullToRefresh);
layoutManager = new GridLayoutManager(getApplicationContext(),4);
recyclerView.setLayoutManager(layoutManager);
arrayList = new ArrayList<>();
videoAdapter = new VideoAdapter(getApplicationContext(),arrayList,Video_Main.this);
recyclerView.setAdapter(videoAdapter);
fetch_videos();
}
private void fetch_videos()
{
Uri uri;
Cursor cursor;
int column_index_data,thum;
String absolutePathImage = null;
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = {
MediaStore.MediaColumns.DATA,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media._ID,
MediaStore.Video.Thumbnails.DATA
};
String selection=MediaStore.Video.Media.DATA +" like?";
String[] selectionArgs=new String[]{"%Paint App%"};
String orderBy = MediaStore.Images.Media.DATE_TAKEN;
cursor = getApplicationContext().getContentResolver().query(uri,projection,selection,selectionArgs,orderBy +" DESC");
String root = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
thum = cursor.getColumnIndexOrThrow(MediaStore.Video.Thumbnails.DATA);
while(cursor.moveToNext())
{
absolutePathImage = cursor.getString(column_index_data);
VideoModel videoModel = new VideoModel();
videoModel.setBoolean_selected(false);
videoModel.setStr_path(absolutePathImage);
videoModel.setStr_thumbnail(cursor.getString(thum));
arrayList.add(videoModel);
}
videoAdapter.setVideoList(arrayList);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.parse(root + "/Paint App")));
}
}
You need to create a method in the adapter like,
public void setVideoList(YourArray arrayList){
this.yourList.clear();
this.yourList.addAll(arrayList);
notifyDataSeChanged();
}
then remove below lines and add it outside the method but above that method,
VideoAdapter videoAdapter = new
VideoAdapter(getApplicationContext(),arrayList,Video_Main.this);
recyclerView.setAdapter(videoAdapter);
Also, call the method from adapter from where you removed the lines,
videoAdapter.setVideoList(arrayList);
then when you add record the file just call the method again fetch_videos(); It will work.
Thanks for the help,i got the solution my sendBroadcast was wrong.It should be
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(file)));
Related
I am trying to implement a feature like Instagram or WhatsApp, where the thumbnail of a single image that exists in a folder in android, is shown on top of a list item, more like a sample of what kinds of image are in the folder.
Help me to understand this feature.
How I implemented it. It might not be the best though, but it works.
I fetched the URIs of all the images using MediaStore, you can learn how to use it here.
The First step was done in a background thread to prevent it from blocking the UI thread.
I sorted out the images I got, grouping them in a List<Image>, which would represent a single directory.
I then added the List<Image> into a List<List<Image>>, which served as the overall images that were fetched and have their total size which I used later to track the number of images in the directory.
The code is below.
#Override
public void run() {
Uri storageUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
storageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
storageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
// the queries to the MediaStore API (The image details or metadata I need
String[] projection = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DISPLAY_NAME};
// now query the MediaStore API using ContentResolver
Cursor imgCursor = getApplicationContext().getContentResolver().query(storageUri, projection, null, null, null);
int bucketId = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int imgSize = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE);
int name = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
int bucketName = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
// directoryDictionary is a temporary list of directory names that was found, while querying the MediaStore API
List<String> directoryDictionary = new ArrayList<>();
// generalList is just a list that would represent a general image list, where all images can be found. Just like Whatsapp
List<Image> generalList = new ArrayList<>();
while (imgCursor.moveToNext()) {
long id = imgCursor.getLong(bucketId);
int size = imgCursor.getInt(imgSize);
String fileName = imgCursor.getString(name);
String folderName = imgCursor.getString(bucketName);
// As recommended by the Android developers doc
Uri contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
// a single image
Image currentImage = new Image(contentUri, size, fileName, folderName);
// add all images to the general image list, but modifying the directory name
Image genImage = new Image(contentUri, size, fileName, "All Media");
generalList.add(genImage);
int directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
// if search result (directoryIndex) passes this test, then it means that there is
// no such directory in list of directory names
if (directoryIndex < 0) {
imageDirectoryList.add(new ArrayList<>());
directoryDictionary.add(folderName);
directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
if (directoryIndex >= 0)
imageDirectoryList.get(directoryIndex).add(currentImage);
} else {
imageDirectoryList.get(directoryIndex).add(currentImage);
}
}
//...then add it if the image list of folder is > 2
if (imageDirectoryList.size() > 2) imageDirectoryList.add(0, generalList);
imgCursor.close();
runOnUiThread(() -> {
// imageAdapter is the RecyclerView's list Adapter.
// notifyDataSetChanged() must be call to refresh list.
imageAdapter.notifyDataSetChanged();
// doViewUpdate was just used to turn on and off the visibility of some views
doViewUpdate();
});
}
The following code gets me image thumbnails from local pictures on the phone/sd cards:
public Task<List<Album>> GetAllAlbumsAndPhotos(object activity)
{
Activity activ = activity as Activity;
List<Album> albums = new List<Album>();
// which image properties are we querying
String[] projection = new String[]
{
MediaStore.Images.Media.InterfaceConsts.BucketId,
MediaStore.Images.Media.InterfaceConsts.BucketDisplayName,
MediaStore.Images.Media.InterfaceConsts.DateTaken,
MediaStore.Images.Media.InterfaceConsts.DateAdded,
MediaStore.Images.Media.InterfaceConsts.Data
};
// Get the base URI for the People table in the Contacts content provider.
AndroidNet.Uri images = MediaStore.Images.Media.ExternalContentUri;
// Make the query.
var cursor = activ.ContentResolver.Query(images,
projection, // Which columns to return
"", // Which rows to return (all rows)
null, // Selection arguments (none)
"" // Ordering
);
if (cursor.MoveToFirst())
{
int bucketColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.BucketDisplayName);
int takenColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.DateTaken);
int addedColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.DateAdded);
int dataColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data);
do
{
.
.
.
} while (cursor.MoveToNext());
}
return Task.FromResult(albums);
}
How do I include Video thumbnails? Can It be done with the same code or does it have to be done independently from this block of code?
I have a listview that loads information from sqlite database. The information should load image this way:
This is the code for the listview activity:
private void populateListViewFromDB() {
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_DATE, DBAdapter.KEY_IMG, DBAdapter.KEY_FAVCOLOUR};
int[] toViewIDs = new int[]
{R.id.item_date, R.id.item_icon, R.id.item_kcal};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.listViewFromDB);
myList.setAdapter(myCursorAdapter);
}
Theoretically, I'm trying to save the string "snapPath" to the field "KEY_IMG" and load the image into imageview "item_icon". If the user does not snap a photo, by default, the imageview will load a drawable instead.
At the Add activity page, I added a string and save that string to the database:
String snapPath = "res/drawable-xxhdpi/ic_launcher.png"; //by default it will load a drawable
myDb.insertRow(date, snapPath, kcal+" kcal"); //saves into database
Also in Add activity page, the code for capturing and saving the image into my phone:
private void doTakePicture() {
// create a File object for the parent directory
File newDir = new File( Environment.getExternalStorageDirectory(), "/myFoodDiary/snaps");
newDir.mkdirs();
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//for file name
Date cDate = new Date();
final String fDate = new SimpleDateFormat("yyyyMMMd").format(cDate);
final String fTime = new SimpleDateFormat("HHmmss").format(cDate);
String snapName = "mFD-" + fDate + fTime + ".jpg";
fileJpeg = new File(newDir, snapName);
snapPath = "/myFoodDiary/snaps/"+String.valueOf(snapName);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(fileJpeg));
startActivityForResult(takePictureIntent, TAKE_PIC_REQ);
}
Thanks in advance!
To customize whether to draw a bitmap from storage or a drawable from your resources, you can't use SimpleCursorAdapter anymore. You need to derive a new class from CursorAdapter and use that.
Conditionally loading the images is not as trivial as it seems. I recommend using the Android Query library image loading methods which support placeholders, fallbacks, and asynchronous loading - just what you need.
I have created a Project having many activities. One activity is to record the video, that is working fine. I can see the recorded video in my specified folder without restart my tablet.
But when I try to find all the videos in that folder in some other activity using query, see code below. Then I can't see my recorded video until I restart my tablet. I can see just old recorded videos before starting my tablet. I couldn't understand this strange behavior.
Can anyone put some light on this issue??
Thanks.
private void initVideosId() { // getting the videos id in Video Folder of SD Card
try {
// Here we set up a string array of the thumbnail ID column we want
// to get back
String[] proj = { _ID };
//Querying for the videos in VideoGallery folder of SD card
// Now we create the cursor pointing to the external thumbnail store
_cursor = managedQuery(_contentUri, proj, // Which columns to return
MEDIA_DATA + " like ? ", // WHERE clause; which rows to
// return (all rows)
new String[] { "%VideoGallery%" }, // WHERE clause selection
// arguments (none)
null); // Order-by clause (ascending by name)
int count = _cursor.getCount();
// We now get the column index of the thumbnail id
_columnIndex = _cursor.getColumnIndex(_ID);
// initialize
_videosId = new int[count];
// move position to first element
_cursor.moveToFirst();
for (int i = 0; i < count; i++) {
int id = _cursor.getInt(_columnIndex);
//
_videosId[i] = id;
//
_cursor.moveToNext();
//
}
} catch (Exception ex) {
showToast(ex.getMessage().toString());
}
}
If you stored the file on external storage, you need to use MediaScannerConnection to get the MediaStore to index that file, such as:
MediaScannerConnection.scanFile(
this,
new String[] {file.getAbsolutePath()},
null,
new OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
// do something if you want
}
});
Big picture: GUI shows user a list of their playlists. User picks one. Program passes chosen playlist to next activity which displays the songs in that playlist.
Problem: I can display the playlists and register the users choice, but I can't seem to display the songs of that play list.
Yes, I've see the following questions:
How to query for songs in playlists on Android SDK?
Given an Android music playlist name, how can one find the songs in the playlist?
What is the String 'volumeName' argument of MediaStore.Audio.Playlists.Members.getContentUri referring to?
As you can see in my code, I've done my best to implement those solutions, but to no avail.
Things to keep in mind: I'm testing this on a Galaxy Nexus, so no SDcard. Just internal storage and music in the cloud. I need it to work in any scenario (internal, external, or cloud). It currently works in none of those.
//#SuppressWarnings ("serial)")
public class CreationActivity extends Activity {
private final String [] STAR= {"*"};
//reads in all songs to an array
#Override
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//set layout view and assign to variable
setContentView(R.layout.creation);
TableLayout myLayout = (TableLayout)findViewById(R.id.creationLayout);
try {
Bundle extras = getIntent().getExtras();
if (extras!=null){
//get the desired playlist and ID
String playlist = extras.getString("playlist");
Long playlistID = extras.getLong("playlistID");
ArrayList<song> songs = new ArrayList<song>();
//read in the songs from the playlist
String[] proj = {MediaStore.Audio.Playlists.Members.TITLE,
MediaStore.Audio.Playlists.Members.ARTIST,
MediaStore.Audio.Playlists.Members.DURATION};
//method 1
Cursor songCursor = getContentResolver().query(MediaStore.Audio.Playlists.Members.getContentUri(null,playlistID),
proj,
null,
null,
null);
//method 2
/*
Cursor songCursor = getContentResolver().query(Uri.parse("content://com.google.android.music.MusicContent/playlists/members"),
proj,
null,
null,
null);
*/
//method 3
/*
Uri membersUri = MediaStore.Audio.Playlists.Members.getContentUri("internal", playlistID);
Cursor membersCursor = managedQuery(membersUri, STAR, null, null, null);
*/
//then this part with methods 1 and 2
/*
if (songCursor.getCount() > 0) {
songCursor.moveToFirst();
do {
song currSong = new song();
currSong.title = songCursor.getString(0);
currSong.artist = songCursor.getString(1);
songs.add(currSong);
} while (songCursor.moveToNext());
}
songCursor.close();
*/
//or this part with method 3
/*
membersCursor.moveToFirst();
for(int s= 0; s<membersCursor.getCount(); s++,
membersCursor.moveToNext()){
song currSong = new song();
currSong.title = songCursor.getString(0);
currSong.artist = songCursor.getString(1);
songs.add(currSong);
}
membersCursor.close();
*/
}else{
Toast.makeText(getBaseContext(), "No songs",Toast.LENGTH_LONG).show();
}
} catch (NumberFormatException e){
}
}
}
No errors during compiling. But "Unfortunately Music App has unexpectedly quit." every time.
Thanks for the help!
I figured it out. The key was to use the playlist ID as a string immediately within the URI. See code below.
This is the part that will get the playlist names and IDs:
String[] proj = {MediaStore.Audio.Playlists.NAME, MediaStore.Audio.Playlists._ID};
Uri playlistUri = Uri.parse("content://com.google.android.music.MusicContent/playlists");
Cursor playlistCursor = getContentResolver().query(playlistUri, proj, null, null, null);
if (playlistCursor.getCount() > 0) {
playlistCursor.moveToFirst();
do {
nameList.add(playlistCursor.getString(0));
idList.add(playlistCursor.getLong(1));
} while (playlistCursor.moveToNext());
}
Then once you have the playlist ID you can query for the songs in the playlist. This is the part of code that actually queries for the info and puts it all in an array list. NOTE: "song" is a class I have defined elsewhere, where readSong is a method that assigns values to various values (title, artist, etc).
ArrayList<song> songs = new ArrayList<song>();
//read songs into library from the correct playlist
String[] proj = {MediaStore.Audio.Playlists.Members.TITLE, MediaStore.Audio.Playlists.Members.ARTIST, MediaStore.Audio.Playlists.Members.DURATION, MediaStore.Audio.Playlists.Members._ID};
Uri songUri = Uri.parse("content://com.google.android.music.MusicContent/playlists/" + playlistID + "/members");
Cursor songCursor = getContentResolver().query(songUri, proj, null, null, null);
if (songCursor.getCount() > 0) {
songCursor.moveToFirst();
do {
//create dummy song
song currSong = new song();
//read info to dummy var
currSong.readSong(songCursor);
//add instance to collection
songs.add(currSong);
} while (songCursor.moveToNext());
}
songCursor.close();
I hope this helps anybody else who was struggling with this!! Let me know if you have any comments on my method or ways to make it better!