CursorWrapperInner: Cursor finalized without prior close() - android

I have built a rss news app. It is working fine upto some point with some bugs. Problem is content provider is not adding new News for some rss feeds and getting Cursor finalized without prior close() error in logs. I am refreshing the feed in background IntentService. Need to improve performance if possible.
private int refreshLocalFeed(Feeds feeds) throws RemoteException, OperationApplicationException {
LogMessage.d("feed refresh:", feeds.getCategoryId() + " : " + feeds.getName());
Call<RSSFeed2> call = api.loadOwnRssFeed(feeds.getUrl());
ContentResolver cr = MyApp.getAppContext().getContentResolver();
int success = 0;
try {
Response<RSSFeed2> response = call.execute();
RSSFeed2 rssFeed = response.body();
if (rssFeed != null) {
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
Collections.reverse(rssFeed.getArticleList());
for (Article article : rssFeed.getArticleList()) {
Cursor c = null;
try {
c = cr.query(DbContract.EntryColumns.CONTENT_URI, new String[]{DbContract.EntryColumns._ID}, DbContract.EntryColumns.CATEGORYID + "=? AND " + DbContract.EntryColumns.LINK + "=?",
new String[]{feeds.getCategoryId(), article.getLink()}, null);
} catch (Exception e) {
e.printStackTrace();
}
ContentValues values = new ContentValues();
values.put(DbContract.EntryColumns.TITLE, article.getTitle());
values.put(DbContract.EntryColumns.DESCRIPTION, article.getDescription());
values.put(DbContract.EntryColumns.DATE, article.getPubDate());
values.put(DbContract.EntryColumns.AUTHOR, getString(R.string.app_name));
values.put(DbContract.EntryColumns.FETCH_DATE, System.currentTimeMillis());
values.put(DbContract.EntryColumns.CATEGORYID, feeds.getCategoryId());
values.put(DbContract.EntryColumns.GUID, article.getGuid());
String alternateImageUrl = getImageUrl(article.getDescription());
if (article.getThumbnail() != null && !article.getThumbnail().isEmpty()) {
values.put(DbContract.EntryColumns.IMAGE_URL, article.getThumbnail());
} else if (!alternateImageUrl.isEmpty()) {
values.put(DbContract.EntryColumns.IMAGE_URL, getImageUrl(article.getDescription()));
}
values.put(DbContract.EntryColumns.LINK, article.getLink());
if (c != null && c.getCount() > 0) {
operations.add(ContentProviderOperation.newUpdate(DbContract.EntryColumns.CONTENT_URI)
.withSelection(DbContract.EntryColumns._ID, new String[]{String.valueOf(c.getInt(c.getColumnIndexOrThrow(DbContract.EntryColumns._ID)))})
.withValues(values)
.build());
c.close();
} else {
operations.add(ContentProviderOperation.newInsert(DbContract.EntryColumns.CONTENT_URI)
.withValues(values)
.build());
}
}
ContentProviderResult[] results = cr.applyBatch(DbContract.AUTHORITY, operations);
for (ContentProviderResult result : results) {
if (result.uri != null) {
success++;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return success;
}
edit
if (c != null) {
if (c.getCount() > 0) {
operations.add(ContentProviderOperation.newUpdate(DbContract.EntryColumns.CONTENT_URI)
.withSelection(DbContract.EntryColumns._ID, new String[]{String.valueOf(c.getInt(c.getColumnIndexOrThrow(DbContract.EntryColumns._ID)))})
.withValues(values)
.build());
}
c.close();
} else {
operations.add(ContentProviderOperation.newInsert(DbContract.EntryColumns.CONTENT_URI)
.withValues(values)
.build());
}

Related

Getting "DownloadManager.STATUS_SUCCESSFUL" even after download not successful (when insufficient space)

I am always getting COLUMN_STATUS as STATUS_SUCCESSFUL even it fails due to insufficient space:
#Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
Utils.log(TAG, "Intent is NULL");
return;
}
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
DownloadManager downloadManager = (DownloadManager)
context.getSystemService(Context.DOWNLOAD_SERVICE);
long referenceId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, -1L);
if (downloadManager != null) {
DownloadManager.Query dmQuery = new DownloadManager.Query();
dmQuery.setFilterById(referenceId);
try (Cursor cursor = downloadManager.query(dmQuery)) {
if (cursor != null && cursor.getCount() > 0) {
// The error is here
int columnIndex =cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (cursor.moveToFirst() && cursor.getInt(columnIndex) == DownloadManager.STATUS_SUCCESSFUL) {
} else {
Log.e(TAG, "fail");
}
}
} catch (Exception exception) {
Log.e(TAG, exception);
}
}
}
}
If your connection timeouts, you will get FAILED.
If it fails due to insufficient space, check the query columns COLUMN_TOTAL_SIZE_BYTES and COLUMN_BYTES_DOWNLOADED_SO_FAR to check if equal.
int bytes_total = cur.getInt(cur.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
int bytes_downloaded = cur.getInt(cur.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));

How to access Device song from internal memoy

I am new to android development here and I want to open internal memory from my app. But it is open on all devices except Samsung device. It's showing fine on Motorola device, other phones and in Emulator also. I am getting null here: if (scanFolder == null) {return null;}
public List<Folder> loadInBackground() {
List<Folder> folderList = new ArrayList<>();
List<Song> songList = new ArrayList<>();
// Permission Check Runtime For M and above
if (PermissionChecker.checkCallingOrSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PermissionChecker.PERMISSION_GRANTED) {
FileExtensionFilter mFileExtensionFilter = new FileExtensionFilter(Constants.fileExtensions);
if (dir != null) {
File[] scanFolder = dir.listFiles(mFileExtensionFilter);
// Getting Null over here in Samsung Device scanFolder getting null
if (scanFolder == null) {
return null;
}
// Get Folder List
for (File aScanFolder : scanFolder) {
Folder folder = new Folder();
Cursor cursor = getContext().getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Audio.Media.DATA}, MediaStore.Audio.Media.DATA + " like ? ", new String[]{"%" + aScanFolder.getAbsolutePath() + "%"}, null);
if (cursor != null) {
int count = cursor.getCount();
if (count != 0) {
if (!aScanFolder.isDirectory()) {
String path = aScanFolder.getAbsolutePath();
Song song = Helper.getSongData(Extras.getInstance().getSongSortOrder(), getContext(), path);
songList.add(song);
}
if (!aScanFolder.getAbsolutePath().startsWith("/d")) {
Log.e("FolderLoader", "Path --> " + aScanFolder.getAbsolutePath());
folder.setFile(aScanFolder);
folder.setFileCount(count);
folder.setSongList(songList);
folderList.add(folder);
}
}
}
if (cursor != null) {
cursor.close();
}
}
Collections.sort(folderList, new Comparator<Folder>() {
#Override
public int compare(Folder f1, Folder f2) {
if ((f1.getFile().isDirectory() && f2.getFile().isDirectory()))
return f1.getFile().getName().compareToIgnoreCase(f2.getFile().getName());
else if (f1.getFile().isDirectory() && !f2.getFile().isDirectory())
return -1;
else if (!f1.getFile().isDirectory() && f2.getFile().isDirectory())
return 1;
else if (!f1.getFile().isDirectory() && !f2.getFile().isDirectory())
return f1.getFile().getName().compareToIgnoreCase(f2.getFile().getName());
else return 0;
}
});
if (!dir.getAbsolutePath().equals("/")) {
Folder folder = new Folder();
if (dir.getParentFile() != null) {
folder.setFile(dir.getParentFile());
Log.e("FolderLoader", dir.getParentFile().getAbsolutePath());
folderList.add(0, folder);
}
}
}
return folderList;
} else {
// Error Message
Log.d("Folder", "Permission not granted");
return Collections.emptyList();
}
}
I am getting this Screen UI in Samsung Device.
Getting All songs in Other device except Samsung Device

iText Pdf form concatenation is not happening as expected. Furthur behaving unexpectedly

With reference to For merging documents
tried implementing this. But first page is showing as expected, next pages will be like half filled and showing without any pdf form backgound i.e of form kind.
Below is my code snippets..
private void addInfo() {
PdfReader reader = null, readerPage = null, pdfReaderExtraPage = null, pdfReaderExtraPage1 = null, readerD = null;
//PdfCopyFields copy = null, copyD = null;
FileOutputStream fosResDoc, fosFinalDoc;
int indirectLaborDocCount = 1;
int equipDocCount = 1;
Document document = null, document2 = null;
PdfCopy copyTemp = null, copyTemp2 = null;
try {
String resultDocPath = Constants.FOLDER_PATH + "ResultDoc.pdf";
fosResDoc = new FileOutputStream(resultDocPath);
reader = new PdfReader(new FileInputStream(Constants.strFilePath));
//copy = new PdfCopyFields(fosResDoc);
//copy.addDocument(reader);
//Before this method i already set values of form for first page. This method is to add extra data/pages if any.
//Add here am adding that using addDocument.
document = new Document();
copyTemp = new PdfSmartCopy(document, fosResDoc);
copyTemp.setMergeFields();
document.open();
copyTemp.addDocument(reader);
boolean isNeededStudentComments = ((strStudentComments.length() > 0) && (strStudentComments.length() > (StudentCommentsMaxLength * StudentCommentsMaxLines)));
boolean isNeededTeacherComments = ((strTeacherComments.length() > 0) && (strTeacherComments.length() > (TeacherCommentsMaxLength * TeacherCommentsMaxLines)));
if (isNeededTeacherComments) {
int commentsTableCount = 1;
do {
String extraPagePath = Constants.FOLDER_PATH + "ExtraPage" + commentsTableCount + ".pdf";
commentsTableCount++;
readerPage = new PdfReader(Constants.strFilePath);
stamper = new PdfStamper(readerPage, new FileOutputStream(extraPagePath), PdfWriter.VERSION_1_5);
readerPage.setPageContent(1, readerPage.getPageContent(1));
stamper.close();
if (isNeededTeacherComments && (strTeacherComments.length() > 0)) {
fillTeacherComments();
}
changePdfFieldName(extraPagePath, commentsTableCount - 1);
pdfReaderExtraPage1 = new PdfReader(extraPagePath);
List<Integer> lst = new ArrayList<>();
lst.add(1);
copy.addDocument(pdfReaderExtraPage1, lst);
} while (populatedTeacherCommentsLength < strTeacherComments.length());
}
if (isNeededStudentComments) {
int commentsTableCount = 1;
do {
String extraPagePath = Constants.FOLDER_PATH + "ExtraPage" + commentsTableCount + ".pdf";
commentsTableCount++;
readerPage = new PdfReader(Constants.strFilePath);
stamper = new PdfStamper(readerPage, new FileOutputStream(extraPagePath), PdfWriter.VERSION_1_5);
readerPage.setPageContent(1, readerPage.getPageContent(1));
stamper.close();
if (isNeededStudentComments && (strStudentComments.length() > 0)) {
fillTeacherComments();
}
changePdfFieldName(extraPagePath, commentsTableCount - 1);
pdfReaderExtraPage1 = new PdfReader(extraPagePath);
List<Integer> lst = new ArrayList<>();
lst.add(1);
copyTemp.addDocument(pdfReaderExtraPage1);
} while (populatedStudentCommentsLength < strStudentComments.length());
}
copyTemp.close();
fosResDoc.close();
readerD = new PdfReader(new FileInputStream(resultDocPath));
fosFinalDoc = new FileOutputStream(Constants.strFilePath);
document2 = new Document();
copyTemp2 = new PdfSmartCopy(document2, fosFinalDoc);
document2.open();
copyTemp2.addDocument(readerD);
fosFinalDoc.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(document != null)
document.close();
if(document2 != null)
document2.close();
if(reader != null) { reader.close(); }
if(readerPage != null) { readerPage.close(); }
if(pdfReaderExtraPage != null) { pdfReaderExtraPage.close(); }
if(pdfReaderExtraPage1 != null) { pdfReaderExtraPage1.close(); }
if(readerD != null) { readerD.close(); }
if(copyTemp != null) { copyTemp.close();}
if(copyTemp2 != null) { copyTemp2.close(); }
try {
if(outputStream != null) { outputStream.close(); outputStream = null; }
} catch (IOException ie) {ie.printStackTrace();}
if(form != null) form = null;
}
}
private void fillTeacherComments() {
PdfReader pdfReaderExtraPage = null;
FileOutputStream fileOuputStream = null;
String tmpNotes = "";
try {
pdfReaderExtraPage = new PdfReader(extraPagePath);
outputStream = new ByteArrayOutputStream();
stamper = new PdfStamper(pdfReaderExtraPage, outputStream);
form = stamper.getAcroFields();
form.setField(fieldKey, "Some information String");
stamper.close();
fileOuputStream = new FileOutputStream(extraPagePath);
fileOuputStream.write(outputStream.toByteArray());
fileOuputStream.close();
} catch(Exception e) {
System.out.println("fillExtraComments(): " +e.toString());
} finally {
if(pdfReaderExtraPage != null) { pdfReaderExtraPage.close(); }
try {
if(outputStream != null) { outputStream.close(); outputStream = null; }
} catch (Exception e) {e.printStackTrace();}
if(form != null) form = null;
}
}
My requirement is that, i have two comments tables in pdf form and max we have only 8 rows, 4 for one table other for other table.
And in code level i have two comments arrays of size 10 each. Then in first page am addign 5 values from each array to form tables.
Next am iterating array one individually and adding to document with name abc.doc. And iterating other array individually and added with name abc.doc
So, these doc should concatenate and fill 5 rows in two table each of same page.But first page is showing as expected, next pages will be like half filled and showing without any pdf form backgound i.e of form kind.

Why I cant't get the video duration from MediaStore?

On one of my device, the following code can't make my video appear in Gallery:
File file = new File(path);
Uri uri = Uri.fromFile(file);
Intent scanFileIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
activity.sendBroadcast(scanFileIntent);
So I use scanFile explicitly:
android.media.MediaScannerConnection.scanFile(activity, new String[]{file.getAbsolutePath()},
new String[]{"video/" + mMimeType}, null);
When my video is xxx.mpeg4, the value of mMimeType is mp4, the result is that the video can appear in MediaStore but I can't get the duration later(the returned value is always 0). Need help on this.
public static long[] getVideoDetail(Context context, Uri uri) {
long[] result = new long[] {DEFAULT_VIDEO_FRAME_WIDTH, DEFAULT_VIDEO_FRAME_HEIGHT, -1};
if(uri == null || (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))) {
return result;
}
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION, MediaStore.Video.VideoColumns.DURATION};
Cursor cursor = null;
boolean success = false;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor.moveToFirst()) {
String resolution = cursor.getString(0);
if(!StringUtils.isEmpty(resolution)) {
int index = resolution.indexOf('x');
result[0] = Integer.parseInt(resolution.substring(0, index));
result[1] = Integer.parseInt(resolution.substring(index + 1));
if(result[0] != 0 && result[1] != 0) {
success = true;
}
if(result[0] > result[1]) {
swap(result, 0, 1);
}
}
result[2] = cursor.getLong(1);
if(result[2] >= 0 && success) {
success = true;
} else {
success = false;
}
}
if (null != cursor) {
cursor.close();
}
}
catch (Exception e) {
// do nothing
} finally {
try {
if (null != cursor) {
cursor.close();
}
} catch (Exception e2) {
// do nothing
}
}
if (!success) {
try {
ContentResolver contentResolver = context.getContentResolver();
String selection = MediaStore.Images.Media._ID + "= ?";
String id = uri.getLastPathSegment();
String[] selectionArgs = new String[]{ id };
cursor = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null);
if (cursor.moveToFirst()) {
String resolution = cursor.getString(0);
if(!StringUtils.isEmpty(resolution)) {
int index = resolution.indexOf('x');
result[0] = Integer.parseInt(resolution.substring(0, index));
result[1] = Integer.parseInt(resolution.substring(index + 1));
if(result[0] > result[1]) {
swap(result, 0, 1);
}
}
result[2] = cursor.getLong(1);
}
if (null != cursor) {
cursor.close();
}
} catch (Exception e) {
// do nothing
} finally {
try {
if (cursor != null) {
cursor.close();
}
} catch (Exception e) {
// do nothing
}
}
}
if(result[0] <= 0) {
result[0] = DEFAULT_VIDEO_FRAME_WIDTH;
}
if(result[1] <= 0) {
result[1] = DEFAULT_VIDEO_FRAME_HEIGHT;
}
return result;
}
As I see in your code you are requesting duration in your projection
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION, MediaStore.Video.VideoColumns.DURATION};
now you just need to retrieve it from the cursor like shown below:
long timeInMs = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DURATION));
get help from MediaPlayer :
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(context, Uri.parse(uri));
} catch (IOException e) {
Log.d("-MS-","Cannot parse url");
e.printStackTrace();
}
int duration= mp.getDuration();
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION,duration};
I always get Duration by MediaPlayer.

How to find mp3 files from sdcard in android programatically

I am new to android programming so can anyone please help me to find all .mp3 files in my android device.
You should use MediaStore. Here is an example code i'm using for something similar:
private static ArrayList<SongModel> LoadSongsFromCard() {
ArrayList<SongModel> songs = new ArrayList<SongModel>();
// Filter only mp3s, only those marked by the MediaStore to be music and longer than 1 minute
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0"
+ " AND " + MediaStore.Audio.Media.MIME_TYPE + "= 'audio/mpeg'"
+ " AND " + MediaStore.Audio.Media.DURATION + " > 60000";
final String[] projection = new String[] {
MediaStore.Audio.Media._ID, //0
MediaStore.Audio.Media.TITLE, //1
MediaStore.Audio.Media.ARTIST, //2
MediaStore.Audio.Media.DATA, //3
MediaStore.Audio.Media.DISPLAY_NAME
};
final String sortOrder = MediaStore.Audio.AudioColumns.TITLE
+ " COLLATE LOCALIZED ASC";
Cursor cursor = null;
try {
// the uri of the table that we want to query
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; //getContentUriForPath("");
// query the db
cursor = _context.getContentResolver().query(uri,
projection, selection, null, sortOrder);
if (cursor != null) {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
//if (cursor.getString(3).contains("AwesomePlaylists")) {
SongModel GSC = new SongModel();
GSC.ID = cursor.getLong(0);
GSC.songTitle = cursor.getString(1);
GSC.songArtist = cursor.getString(2);
GSC.path = cursor.getString(3);
// This code assumes genre is stored in the first letter of the song file name
String genreCodeString = cursor.getString(4).substring(0, 1);
if (!genreCodeString.isEmpty()) {
try {
GSC.genre = Short.parseShort(genreCodeString);
} catch (NumberFormatException ex) {
Random r = new Random();
GSC.genre = (short) r.nextInt(4);
} finally {
songs.add(GSC);
}
}
//}
cursor.moveToNext();
}
}
} catch (Exception ex) {
} finally {
if (cursor != null) {
cursor.close();
}
}
return songs;
}
Of course . you can . Code not tested.
File dir =new File(Environment.getExternalStorageDirectory());
if (dir.exists()&&dir.isDirectory()){
File[] files=dir.listFiles(new FilenameFilter(){
#Override
public boolean accept(File dir,String name){
return name.contains(".mp3");
}
});
}
You can use recursive searching. Use this function with path of directory where you wanna start search .mp3 files (for example "/mnt/sdcard").
public Vector<String> mp3Files = new Vector<String>();
private void searchInDirectory(String directory)
{
File dir = new File(directory);
if(dir.canRead() && dir.exists() && dir.isDirectory())
{
String []filesInDirectory = dir.list();
if(filesInDirectory != null)
{
for(int i=0; i<filesInDirectory.length; i++)
{
File file = new File(directory+"/"+filesInDirectory[i]);
if(file.isFile() && file.getAbsolutePath().toLowerCase(Locale.getDefault()).endsWith(".mp3"))
{
mp3Files.add(directory+"/"+filesInDirectory[i]);
}
else if(file.isDirectory() )
{
searchInDirectory(file.getAbsolutePath());
}
}
}
}
}
public ArrayList<String> searchMP3File(ArrayList<String> aListFilePath, String rootPath) {
File rootFile = new File(rootPath);
File[] aRootFileFilter = rootFile.listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".mp3"))
return true;
else
return false;
}
});
if(aRootFileFilter != null && aRootFileFilter.length > 0) {
for(int i = 0; i < aRootFileFilter.length; i++) {
aListFilePath.add(aRootFileFilter[i].getPath());
}
}
File[] aRootFile = rootFile.listFiles();
for(int i = 0; i < aRootFile.length; i++) {
if(aRootFile[i].isDirectory()) {
ArrayList<String> aListSubFile = searchMP3File(aListFilePath, aRootFile[i].getPath());
if(aListSubFile != null && aListSubFile.size() > 0)
aListFilePath = aListSubFile;
}
}
return aListFilePath;
}
private String[] videoExtensions;
videoExtensions = new String[2];
videoExtensions[0] = "mp3";
videoExtensions[1] = "3gp";
After this declaration in your onCreate() method, set below code in some method and call it. Do changes as per your need in my code.
try {
File file = new File("mnt/sdcard/DCIM/Camera");
File[] listOfFiles = file.listFiles();
videoArray = new ArrayList<HashMap<String, String>>();
videoHashmap = new HashMap<String, String>();
for (int i = videoIndex; i < listOfFiles.length; i++) {
File files = listOfFiles[i];
rowDataVideos = new HashMap<String, String>();
for (String ext : videoExtensions) {
if (files.getName().endsWith("." + ext)) {
videoHashmap.put("Video", files.getAbsolutePath());
videoArray.add(videoHashmap);
fileSize = files.length();
fileSizeInMb += convertSize(fileSize, MB);
thumb = ThumbnailUtils.createVideoThumbnail(files.getAbsolutePath(), MediaStore.Images.Thumbnails.MINI_KIND);
if (thumb != null) {
createTempDirectory();
try {
FileOutputStream out = new FileOutputStream(audiofile);
thumb.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// Tue Apr 23 16:08:28 GMT+05:30 2013
lastModDate = new Date(files.lastModified()).toString();
dateTime = (dateToMilliSeconds(lastModDate) / 1000L);
rowDataVideos.put(VIDEOPATH, files.getAbsolutePath());
rowDataVideos.put(VIDEOSTATUS, "0");
rowDataVideos.put(VIDEOSIZEINMB, String.valueOf(fileSizeInMb));
rowDataVideos.put(VIDEODATE, String.valueOf(dateTime));
if (dateTime > (RESPONSE_TIMESTAMP_VIDEO / 1000L)) {
dataProvider.InsertRow(VIDEOS, rowDataVideos);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}

Categories

Resources