android.database.sqlite.SQLiteException: no such column: bucket_display_name - java

I was trying to get buckets having audio files using MediaStore. This is working fine on Android 10 API 29 but not working previous Android versions. I've attached a screenshot of working example on Android 10 API 29.
Caused by: android.database.sqlite.SQLiteException: no such column:
bucket_display_name (code 1 SQLITE_ERROR): , while compiling: SELECT
bucket_display_name, bucket_id FROM audio ORDER BY date_added ASC
logcat.
Caused by: android.database.sqlite.SQLiteException: no such column: bucket_display_name (code 1 SQLITE_ERROR): , while compiling: SELECT bucket_display_name, bucket_id FROM audio ORDER BY date_added ASC
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:179)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
at android.content.ContentResolver.query(ContentResolver.java:802)
at android.content.ContentResolver.query(ContentResolver.java:752)
at android.content.ContentResolver.query(ContentResolver.java:710)
at com.aisar.mediaplayer.fragments.AudioFolderFragment$AsyncVideoFolderLoader.doInBackground(AudioFolderFragment.java:148)
at com.aisar.mediaplayer.fragments.AudioFolderFragment$AsyncVideoFolderLoader.doInBackground(AudioFolderFragment.java:130)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:764) 
Code:
class AsyncVideoFolderLoader extends AsyncTask<String, String, List<ModelAudioFolder>> {
private String sortBy;
public AsyncVideoFolderLoader(String sortBy) {
this.sortBy = sortBy;
}
#Override
protected List<ModelAudioFolder> doInBackground(String... strings) {
List<ModelAudioFolder> videoItems = new ArrayList<>();
videoItems.clear();
final HashMap<String, ModelAudioFolder> output = new HashMap<>();
final Uri contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
final String[] projection = {MediaStore.Audio.Media.BUCKET_DISPLAY_NAME, MediaStore.Audio.Media.BUCKET_ID};
try (final Cursor cursor = getActivity().getContentResolver().query(
contentUri,
projection,
null,
null,
"" + sortBy)) {
if ((cursor != null) && (cursor.moveToFirst())) {
final int columnBucketName = cursor.getColumnIndex(MediaStore.Audio.Media.BUCKET_DISPLAY_NAME);
final int columnBucketId = cursor.getColumnIndex(MediaStore.Audio.Media.BUCKET_ID);
do {
final String bucketName = cursor.getString(columnBucketName);
final String bucketId = cursor.getString(columnBucketId);
if (!output.containsKey(bucketId)) {
final int count = getCount(contentUri, bucketId);
final ModelAudioFolder item = new ModelAudioFolder(
"" + bucketId,
"" + bucketName,
"",
"" + getPath(bucketId),
"" + count
);
output.put(bucketId, item);
videoItems.add(item);
}
} while (cursor.moveToNext());
}
}
return videoItems;
}
private int getCount(#NonNull final Uri contentUri, #NonNull final String bucketId) {
try (final Cursor cursor = getActivity().getContentResolver().query(contentUri,
null, MediaStore.Audio.Media.BUCKET_ID + "=?", new String[]{bucketId}, null)) {
return ((cursor == null) || (cursor.moveToFirst() == false)) ? 0 : cursor.getCount();
}
}
private String getPath(String BUCKET_ID) {
String path = "";
String selection = null;
String[] projection = {
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.BUCKET_ID
};
Cursor cursor = getActivity().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
while (cursor.moveToNext()) {
if (BUCKET_ID.equals(cursor.getString(1))) {
//add only those videos that are in selected/chosen folder
path = cursor.getString(0);
}
}
return path;
}
#Override
protected void onPostExecute(List<ModelAudioFolder> audioFolderList) {
super.onPostExecute(audioFolderList);
if (audioFolderList.size() <= 0) {
noFoldersRl.setVisibility(View.VISIBLE);
foldersRl.setVisibility(View.GONE);
} else {
noFoldersRl.setVisibility(View.GONE);
foldersRl.setVisibility(View.VISIBLE);
}
Log.d("FoldersSize", "onPostExecute: " + audioFolderList.size());
adapterAudioFolder = new AdapterAudioFolder(getActivity(), audioFolderList, dashboardActivity);
foldersRv.setAdapter(adapterAudioFolder);
}
}
...

The reason of the exception is BUCKET_DISPLAY_NAME. It is added in API 29. Before this we were using DISPLAY_NAME for API 28 & below. Please refer to the docs BUCKET_DISPLAY_NAME.
For solution you can write conditions according to current API level. And for getting folder name, you can use RELATIVE_PATH.

In API verions <= 28 BUCKET_DISPLAY_NAME only exists for images and videos, so, accesible via MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME or MediaStore.Vidos.VideoColumns.BUCKET_DISPLAY_NAME.
That said, the solution to get the BUCKET_DISPLAY_NAME for audios in versions bellow 29, is to parse the MediaStore.Files.FileColumns.DATA. This field is deprecated in 29, but still valid in previous versions.
The field contains the actual path + filename, and since a BUCKET_DISPLAY_NAME is in reality the actual parent folder name where a file is located, what you need to do is to remove the file name, and then get the sub-string starting at the last found backward-slash from the path.

I did it my self now. First retrieved all audio files, then separated audio URIs. From audio URIs, I've got Folder Names. I'm posting my solution here so maybe someone else can get benefit from it.
class AsyncVideoFolderLoader extends AsyncTask<String, String, List<ModelAudioFolder>> {
private Cursor cursor;
List<ModelAudioTe> audioList;
private String sortBy;
public AsyncVideoFolderLoader(String sortBy) {
this.sortBy = sortBy;
}
#Override
protected List<ModelAudioFolder> doInBackground(String... strings) {
String selection = null;
String[] projection;
projection = new String[]{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.ALBUM_ID
};
cursor = getActivity().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
audioList = new ArrayList<>();
ModelAudioTe modelAudio;
while (cursor.moveToNext()) {
modelAudio = new ModelAudioTe(
"" + cursor.getString(0),
"" + cursor.getString(1),
"" + cursor.getString(2),
"" + cursor.getString(3),
"" + cursor.getString(4),
"" + cursor.getString(5),
"" + cursor.getString(6),
"" + cursor.getString(7));
audioList.add(modelAudio);
}
//creating audio paths/uris list
ArrayList<String> pathsList = new ArrayList<>();
pathsList.clear();
for (int i = 0; i < audioList.size(); i++) {
String folderName = new File(audioList.get(i).getDATA()).getParentFile().getName();
String folderId = new File(audioList.get(i).getDATA()).getParentFile().getParent();
pathsList.add(folderId + "/" + folderName);
}
//generating folder names from audio paths/uris
List<ModelAudioFolder> folderList = new ArrayList<>();
folderList.clear();
for (int i = 0; i < audioList.size(); i++) {
String folderName = new File(audioList.get(i).getDATA()).getParentFile().getName();
String folderId = new File(audioList.get(i).getDATA()).getParentFile().getParent();
int count = Collections.frequency(pathsList, folderId + "/" + folderName);
String folderRoot;
String folderRoot1 = "";
if (audioList.get(i).getDATA().contains("emulated")) {
folderRoot = "emulated";
} else {
folderRoot = "storage";
}
if (i > 0) {
if (audioList.get(i - 1).getDATA().contains("emulated")) {
folderRoot1 = "emulated";
} else {
folderRoot1 = "storage";
}
}
if (i == 0) {
ModelAudioFolder model = new ModelAudioFolder("" + folderId + "/" + folderName, "" + folderName, "", "" + folderId + "/" + folderName, "" + count);
folderList.add(model);
Log.d("The_Tag1", "onCreate: " + folderName + " " + folderRoot + " " + folderId + "/" + folderName + " " + count);
} else if (
folderName.equals(new File(audioList.get(i - 1).getDATA()).getParentFile().getName())
&&
folderRoot.equals(folderRoot1)
) {
//exclude
} else {
ModelAudioFolder model = new ModelAudioFolder("" + folderId + "/" + folderName, "" + folderName, "", "" + folderId + "/" + folderName, "" + count);
folderList.add(model);
Log.d("The_Tag1", "onCreate: " + folderName + " " + folderRoot + " " + folderId + "/" + folderName + " " + " " + count);
}
}
return folderList;
}
#Override
protected void onPostExecute(List<ModelAudioFolder> audioFolderList) {
super.onPostExecute(audioFolderList);
Log.d("ModelAudioFolder_Size", "Count:" + audioFolderList.size());
try {
if (audioFolderList.size() <= 0) {
noFoldersRl.setVisibility(View.VISIBLE);
foldersRl.setVisibility(View.GONE);
} else {
noFoldersRl.setVisibility(View.GONE);
foldersRl.setVisibility(View.VISIBLE);
}
Log.d("FoldersSize", "onPostExecute: " + audioFolderList.size());
adapterAudioFolder = new AdapterAudioFolder(getActivity(), audioFolderList, dashboardActivity);
foldersRv.setAdapter(adapterAudioFolder);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Related

MediaStore.Audio and ContentResolver.query not getting music

I have a Music player project in Android Studio, and I need to get all music from the device.
But somehow this.getContentResolver().query(); is not getting any music from my device.
In the logcat there is no log, and if I debug the app before the while loop and after it(because it does not enter in the while loop) it says that the cursor does not have any row(mCount = 0)
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
ContentResolver resolver = this.getContentResolver();
String[] projection = {
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST
};
String where = MediaStore.Audio.Media.IS_MUSIC + " != 0";
Cursor c = resolver.query(uri, projection, where, null, null);
if (c != null) {
while (c.moveToNext()) {
String path = c.getString(0);
String name = c.getString(1);
String album = c.getString(2);
String artist = c.getString(3);
Log.e("Name :" + name, " Album :" + album);
Log.e("Path :" + path, " Artist :" + artist);
}
c.close();
}

How to GROUP BY in where clause with ContentProvider?

Helo, I've got this code, which query the instances in calendarcontract:
Uri uri = Uri.parse(CalendarContract.Instances.CONTENT_URI + "/" +
Long.toString(from) + "/" +
Long.toString(to));
String[] mProjection =
{
CalendarContract.Instances._ID,
CalendarContract.Instances.EVENT_ID,
CalendarContract.Instances.CALENDAR_ID,
CalendarContract.Instances.TITLE,
CalendarContract.Instances.EVENT_LOCATION,
CalendarContract.Instances.DESCRIPTION,
CalendarContract.Instances.EVENT_COLOR,
CalendarContract.Instances.DTSTART,
CalendarContract.Instances.DTEND,
CalendarContract.Instances.EVENT_TIMEZONE,
CalendarContract.Instances.EVENT_END_TIMEZONE,
CalendarContract.Instances.DURATION,
CalendarContract.Instances.ALL_DAY,
CalendarContract.Instances.RRULE,
CalendarContract.Instances.RDATE,
CalendarContract.Instances.EXDATE
};
ContentResolver cr2 = this.c.getContentResolver();
String selection2 = "( " + selection_allcalendars + " (" + CalendarContract.Instances.RRULE + " IS NOT NULL) AND (deleted != 1) AND (" + CalendarContract.Instances.ALL_DAY + " = 0))";
Cursor cur2 = cr2.query(uri, mProjection, selection2, null, CalendarContract.Instances.DTSTART + " ASC");
How can I remove double instances from query? I want to use a "GROUP BY" clause, but I don't know how to do that.
Please help me :-)
Thanks!
Edit:
I want to group by EVENT_ID, because I get multiple entries. This ist the whole code I use for recurring events:
ContentResolver cr2 = this.c.getContentResolver();
String selection2 = "( " + selection_allcalendars + " (" + CalendarContract.Instances.RRULE + " IS NOT NULL) AND (deleted != 1) AND (" + CalendarContract.Instances.ALL_DAY + " = 0))";
Cursor cur2 = cr2.query(uri, mProjection, selection2, null, CalendarContract.Instances.DTSTART + " ASC");
ArrayList<String> checkexists = new ArrayList<>();
while (cur2.moveToNext()) {
String eventid = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.EVENT_ID));
if(checkexists.contains(eventid)) {
}
else {
checkexists.add(eventid);
String rrule = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.RRULE));
TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
Long dtstart;
try {
dtstart = Long.parseLong(cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.DTSTART)));
dtstart = tz.getOffset(dtstart) + dtstart;
} catch (NumberFormatException e) {
dtstart = 0l;
}
Long dtend;
try {
dtend = dtstart + RFC2445ToMilliseconds(cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.DURATION)));
/* dtend = Long.parseLong(cur.getString(cur.getColumnIndex(CalendarContract.Events.DTEND)));
dtend = tz.getOffset(dtend) + dtend; */
} catch (NumberFormatException e) {
dtend = 0l;
}
Calendar cal4 = Calendar.getInstance();
cal4.setTimeInMillis(dtstart);
LocalDate localdate = new LocalDate(cal4.get(Calendar.YEAR), cal4.get(Calendar.MONTH) + 1, cal4.get(Calendar.DAY_OF_MONTH));
long calendar_id = Long.valueOf(cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.CALENDAR_ID)));
String id = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances._ID));
String title = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.TITLE));
String eventlocation = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.EVENT_LOCATION));
String description = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.DESCRIPTION));
String eventcolor = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.EVENT_COLOR));
String eventtimezone = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.EVENT_TIMEZONE));
String eventtimezone_end = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.EVENT_END_TIMEZONE));
String duration = cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.DURATION));
int allday = Integer.valueOf(cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.ALL_DAY)));
rrule = "RRULE:" + rrule;
long lastrecurrencetime;
if(rrule.contains("UNTIL")) {
lastrecurrencetime = RruleHelper.getUntil(rrule).getTimeInMillis();
}
else {
lastrecurrencetime = -1;
}
//System.out.println("EEE: " + title + " " + rrule);
try {
ArrayList<ReadEvent> recurrenceevents = new ArrayList<>();
for (LocalDate date : LocalDateIteratorFactory.createLocalDateIterable(rrule, localdate, true)) {
// System.out.println("GGG:" + title + " " + i);
Calendar newcal_from = Calendar.getInstance();
newcal_from.setTimeInMillis(dtstart);
newcal_from.set(Calendar.DAY_OF_MONTH, date.getDayOfMonth());
newcal_from.set(Calendar.MONTH, date.getMonthOfYear() - 1);
newcal_from.set(Calendar.YEAR, date.getYear());
long dtstart_new = newcal_from.getTimeInMillis();
long dtend_new = dtstart_new + RFC2445ToMilliseconds(cur2.getString(cur2.getColumnIndex(CalendarContract.Instances.DURATION)));
if (dtstart_new >= from && dtstart_new <= to) {
ReadEvent newreadevent = new ReadEvent(calendar_id, id, eventid, title, eventlocation, description, eventcolor, dtstart_new, dtend_new, eventtimezone, eventtimezone_end, duration, allday, rrule);
newreadevent.setFirstReccurenceTime(dtstart);
newreadevent.setLastReccurenceTime(lastrecurrencetime);
if(!checkIfAlreadyExits(readevent, newreadevent)) {
//newreadevent.setReccurenceCount(i);
readevent.add(newreadevent);
}
}
if (dtstart_new > to) {
break;
}
}
} catch (Exception e) {
}
}
}

how to import chrome history into android application in android studio?

i want the code to import chrome history into my application in android studio
and i tried to use this code :
String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL };
String chnHistory = Browser.BookmarkColumns.BOOKMARK + " = 0"; // 0 = history,
Cursor mycur = this.managedQuery(Browser.BOOKMARKS_URI, proj,
chnHistory, null, null);
this.startManagingCursor(mycur);
mycur.moveToFirst();
ArrayList<String> array = new ArrayList<String>();
String title = "";
String url = "";
if (mycur.moveToFirst() && mycur.getCount() > 0) {
while (!mycur.isAfterLast()) {
title = mycur.getString(mycur
.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mycur.getString(mycur
.getColumnIndex(Browser.BookmarkColumns.URL));
array.add(title + " : " + url);
mycur.moveToNext();
}
}
if (array.size() > 0) {
for (String string : array) {
Log.d("result ", string);
}
}
but the BookmarkColumns not resolved becuase of the targetSdkVersion 23

How get thumbnails from a specific directory with content provider

I have this code that want to extract all thumbnails but the array result is empty and logically list bitmaps too.Where path is "/emulated/storage/legacy", context is the Activity and the query is with condition. Any Idea? Thanks.
public void getThubmnails() {
String[] cols = {
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns.DISPLAY_NAME
};
Uri uri = MediaStore.Files.getContentUri("external");
Cursor cursor = this.context.getContentResolver().query(
uri,
cols,
MediaStore.Files.FileColumns.DATA + "=?",
new String[] {
path,
},
null
);
cursor.moveToFirst();
int index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID);
int name = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME);
int tipo = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MIME_TYPE);
int path = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA);
String[] result = new String[cursor.getCount()];
while(cursor.moveToNext()) {
result[cursor.getPosition()] = "ID: " + String.valueOf(cursor.getLong(index))
+ " " + "NAME: " + cursor.getString(name)
+ " " + "MIME_TYPE: " + cursor.getString(tipo)
+ " " + "DATA: " + cursor.getString(path);
this.bitmap.add(MediaStore.Images.Thumbnails.getThumbnail(
this.context.getContentResolver(),
cursor.getLong(index),
MediaStore.Images.Thumbnails.MICRO_KIND, null));
}
}

How to check if id is exists in Android?

I want to check if id is exists in SQLIte DB then update that id , if id is not present in SQLite then insert that id. How can i do this. Can someone help how to work with.Thanks to Appreciate.
Here is my Activity code
public void saveResult()
{
AnswerOptions = (RadioButton) findViewById(Options_RadioGroup.getCheckedRadioButtonId());
String str_AnswerOptions = AnswerOptions.getText().toString().trim();
System.out.println("rbVal = " + str_AnswerOptions);
if (str_AnswerOptions.equals(((Datastructure) Vectore_mquestionDatabaseStructure .get(StaticClass.QuestionNumber)).Answer))
{
if (!StaticClass.isTest)
{
try
{
DatabaseHelper databaseHelper = new DatabaseHelper(this.getApplicationContext());
sqdb = databaseHelper.getWritableDatabase();
String strCountQuery = "SELECT question_id, question_type , question_no FROM question_answers where question_id = " + convertVector ;
Cursor cur = sqdb.rawQuery(strCountQuery , null);
if (cur.moveToFirst())
{
int iCount = cur.getCount();
System.out.println("iCount = " + iCount);
if(cur.getCount() <= 0 )
{
String strstrqueType = txtViewQuestiontype.getText().toString().trim();
String str_que = txtViewQuestion.getText().toString().trim();
String str_marks = "1";
databaseHelper.insertQueDetails(strQueLimit, strstrqueType, str_que, str_AnswerOptions, str_marks , strOption_Id);
System.out.println("strQueLimit = " + strQueLimit + ", strstrqueType = " + strstrqueType +" , str_que = " + str_que + " , str_AnswerOptions = " + str_AnswerOptions + ", str_marks = " + str_marks + ", strOption_Id = " + strOption_Id);
Toast.makeText(this, " Right Answer ", Toast.LENGTH_LONG).show();
}
else
{
cur.moveToFirst();
qid = cur.getInt(cur.getColumnIndex("question_id"));
String strQue_Type = cur.getString(cur.getColumnIndex("question_type"));
String strQue_Nomber = cur.getString(cur.getColumnIndex("question_no"));
System.out.println("qid in checkUpdateTable() = " + qid);
System.out.println("strQue_Type in checkUpdateTable() = " + strQue_Type);
System.out.println("strQue_Nomber in checkUpdateTable()= " + strQue_Nomber);
QueId = qid;
databaseHelper.updateAnswerRow(qid, str_AnswerOptions);
}
}
}
catch (SQLiteException se )
{
Log.e(getClass().getSimpleName(), "Could not create or Open the database");
}
finally
{ if (sqdb != null) { sqdb.close();} }
}
}
}
You need to set a constraint on the table to trigger a "conflict" which you then resolve by doing a replace:
CREATE TABLE data (id INTEGER PRIMARY KEY, question_id INTEGER, question_type TEXT, question_no TEXT);
CREATE UNIQUE INDEX data_idx ON data(question_id);
Then you can issue:
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);

Categories

Resources