Can someone help me to create a reminder for an calendar event on programmatically. It works perfectly fine on API level 22, but not on 23 (Marshmallow).
Code:
ContentValues reminderValues = new ContentValues();
reminderValues.put(CalendarContract.Reminders.EVENT_ID, 1);
reminderValues.put(CalendarContract.Reminders.MINUTES, 1);
reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_DEFAULT);
Uri reminderUri = getApplicationContext().getContentResolver()
.insert(CalendarContract.Reminders.CONTENT_URI, reminderValues);
Exception:
SqliteDoneException
private int getPrimaryCalendar() {
// noinspection ResourceType
Cursor managedCursor = getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, new String[]{
CalendarContract.Calendars._ID, CalendarContract.Calendars.IS_PRIMARY}, null, null, null);
int calID = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (managedCursor != null && managedCursor.moveToFirst()) {
do {
calID = managedCursor.getInt(managedCursor.getColumnIndex(CalendarContract.Calendars._ID));
int columnIndex = -1;
try {
columnIndex = managedCursor.getColumnIndex(CalendarContract.Calendars.IS_PRIMARY);
} catch (NullPointerException e) {
LogUtil.d(TAG, e.getMessage());
}
if (columnIndex != -1 && managedCursor.getInt(columnIndex) == 1) {
break;
} else {
calID = 1;
}
} while (managedCursor.moveToNext());
managedCursor.close();
}
}
return calID;
}
Use the default calendar
Related
I am really stuck as I have a cursor that retrieves values from the database but the cursor only returns the last value. I need the cursor to retrieve all values so I can display them all later on. Is there any way as I can return all the data stored through the cursor?
An Example as to whats happening. Eg Click on Button 1 and stores 1 perfectly but once I click on Button 2 and add 1. Button 1 data is not return or retrieved.
Any help would be greatly appreciated.
Execute
The first Cursor is goes through to check all the stored items.
public void exectute() {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
Cursor c = TrackerDb.getStoredItems(getApplicationContext());
if (c != null) {
if (c.moveToFirst()) {
WorkoutDetails details = null;
//if (details != null) mWorkoutDetailsList.add(details);
do {
//if (details != null) mWorkoutDetailsList.add(details);
WorkoutDetails temp = getWorkoutFromCursor(c);
//if (details != null) mWorkoutDetailsList.add(details);
if (details == null) {
details = temp;
continue;
}
//if (details != null) mWorkoutDetailsList.add(details);
if (isSameDay(details.getWorkoutDate(), temp.getWorkoutDate())) {
//if (details != null) mWorkoutDetailsList.add(details);
if (DBG) Log.d(LOG_TAG, "isSameDay().. true");
//details.add(temp);
} else {
mWorkoutDetailsList.add(details);
details = temp;
}
// if (details != null) mWorkoutDetailsList.add(details);
} while (c.moveToNext());
if (details != null) mWorkoutDetailsList.add(details);
if (DBG)
Log.d(LOG_TAG, "AsyncTask: list size " + mWorkoutDetailsList.size());
runOnUiThread(new Runnable() {
#Override
public void run() {
mWorkoutsAdapter.updateList(mWorkoutDetailsList);
}
});
}
c.close();
}
}
});
}
Get Stored Items Code
This is the code which the excute class calls and where the cursor only returns one value.
public static Cursor getStoredItems(Context context) {
DBHelper dbHelper = new DBHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
String[] projection = {ID, TIME, TYPE, DURATION, DATE, POINT};
String orderBy = TIME + " DESC";
Cursor cursor = db.query(TABLE_NAME, projection, null, null, null, null, orderBy);
return cursor;
}
Array
This is the array code where i want the cursor to store its values based on type.
private WorkoutDetails getWorkoutFromCursor(Cursor c) {
long time = c.getLong(c.getColumnIndex(TrackerDb.TIME));
int type = c.getInt(c.getColumnIndex(TrackerDb.TYPE));
int duration = c.getInt(c.getColumnIndex(TrackerDb.DURATION));
int point = c.getInt(c.getColumnIndex(TrackerDb.POINT));
int totalMoney = MoneyActivity.Money.values().length;
int[] points = new int[totalMoney];
int totalActivities = MeditationTrackerActivity.ACTIVITIES.values().length;
int[] durations = new int[totalActivities];
if (type < totalActivities) {
durations[type] = duration;
}
if( type == 0) {
for (int i = 0; i < totalMoney; i++) {
points[type] = point;
}
}
else if ( type == 1) {
for ( int ii = 0; ii < totalMoney; ii++) {
points[type] = point;
}
}
else if ( type == 2) {
for ( int iii = 0; iii < totalMoney; iii++) {
points[type] = point;
}
}
return new WorkoutDetails(time, durations, points);
}
Get Workout From Cursor Code
private static WorkoutDetails getWorkoutFromCursor(Cursor c) {
long time = c.getLong(c.getColumnIndex(TrackerDb.TIME));
int type = c.getInt(c.getColumnIndex(TrackerDb.TYPE));
int duration = c.getInt(c.getColumnIndex(TrackerDb.DURATION));
String date = c.getString(c.getColumnIndex(TrackerDb.DATE));
int point = c.getInt(c.getColumnIndex(TrackerDb.POINT));
int[] durations = new int[MeditationTrackerActivity.ACTIVITIES.values().length];
durations[type] = duration;
int[] points = new int[MoneyActivity.Money.values().length];
points[type] = point;
return new WorkoutDetails(time, durations, date, points);
}
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());
}
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.
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();
}
I am using below code. Its working fine for android 1.6 but its throwing below error for android 2.0 and above version. Please let me know the solution for it.
Error:
01-24 16:55:28.315: ERROR/ActivityThread(208): Failed to find provider info for calendar
01-24 16:55:28.315: ERROR/error(208): Unknown URL content://calendar/events
To read Event:
private void readContent(String uriString) {
Uri uri = Uri.parse(uriString);
Cursor cursor = getContentResolver().query(uri, null, null,
null, null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
String columnNames[] = cursor.getColumnNames();
String value = "";
String colNamesString = "";
do {
value = "";
for (String colName : columnNames) {
value += colName + " = ";
value += cursor.getString(cursor.getColumnIndex(colName))
+ " ||";
}
Log.e("INFO : ", value);
} while (cursor.moveToNext());
}
}
To Add event
private void addEvent(){
try {
ContentValues event = new ContentValues();
event.put("calendar_id", "1");
event.put("title", "tet event");
event.put("description", "hello this is testing of event");
event.put("eventLocation", "Ahmedabad");
Calendar c = Calendar.getInstance();
long date = c.getTimeInMillis();
event.put("dtstart", date);
event.put("dtend", date);
event.put("allDay", 1);
event.put("eventStatus", 1);
event.put("hasAlarm", 1);
Uri eventsUri = Uri.parse("content://calendar/events");
Uri url = getContentResolver().insert(eventsUri, event);
Log.e("uri", url.toString());
} catch (Exception e) {
Log.e("error", e.getMessage());
e.printStackTrace();
}
}
Thanks
You should know, that on new Android versions the URI for Calendar content provider has changed, now you should use content://com.android.calendar/
Yes it´s a crap :(
So if you was using content://calendar/ ,to get successful,now you should use content://com.android.calendar/
If you want to maintain a compatibility across all Android versions of your apps, you will need to handle the Old URI along with the New URI, you can do something like this:
Uri calendarUri;
Uri eventUri;
if (android.os.Build.VERSION.SDK_INT <= 7 )
{
//the old way
calendarUri = Uri.parse("content://calendar/calendars");
eventUri = Uri.parse("content://calendar/events");
}
else
{
//the new way
calendarUri = Uri.parse("content://com.android.calendar/calendars");
eventUri = Uri.parse("content://com.android.calendar/events");
}
But, lets play a bit xDDD
function Uri getCalendarURI(eventUri boolean){
Uri calendarURI = null;
if (android.os.Build.VERSION.SDK_INT <= 7 )
{
calendarURI = (eventUri)?Uri.parse("content://calendar/events"):Uri.parse("content://calendar/calendars");
}
else
{
calendarURI = (eventUri)?Uri.parse("content://com.android.calendar/events"): Uri.parse("content://com.android.calendar/calendars");
}
return calendarURI;
}
Or in one line :
function Uri getCalendarUri(eventUri boolean){
return (android.os.Build.VERSION.SDK_INT <= 7 )?((eventUri)?Uri.parse("content://calendar/events"):Uri.parse("content://calendar/calendars")):(calendarURI = (eventUri)?Uri.parse("content://com.android.calendar/events"): Uri.parse("content://com.android.calendar/calendars"));
}
Note : android.os.Build.VERSION.SDK_INT is available since SDK_INT = 4 i mean Android 1.6,for prior version android.os.Build.VERSION.SDK more info at http://developer.android.com/reference/android/os/Build.VERSION