I'm attempting to update a calendar's event on my phone from my code, but context.getContentResolver().update keeps returning 0, and of course there are no changes made to the event when I look at it in the Calendar app.
I'm getting the event ID, start time, etc with context.getContentResolver().query, and I'm getting unique numbers like 431, 4, 233, etc, so I'm presuming the event IDs I'm using are real.
I understand the official way to do this is to go through Google's servers instead of using update(), but for my implementation it doesn't make sense to do it that way (or even in general, but I digress).
Am I doing something wrong, or am I trying to do something that Android simply isn't going to allow?
Uri updateEventUri = ContentUris.withAppendedId(Uri.parse("content://com.android.calendar/events"), id);
ContentValues cv = new ContentValues();
begin.set(Calendar.HOUR_OF_DAY, arg0.getCurrentHour()); //begin is a java.util.Calendar object
begin.set(Calendar.MINUTE, arg0.getCurrentMinute());
//cv.put("_id", id);
//cv.put("title", "yeahyeahyeah!");
cv.put("dtstart", begin.getTimeInMillis());
int updatedrowcount = context.getContentResolver().update(updateEventUri, cv, null, null);
System.out.println("updated "+updatedrowcount+" rows with id "+id);
A related question was posted here with no replies https://stackoverflow.com/questions/5636350/update-android-calendar-event
Let me know if I can clarify anything; I would really appreciate any input you guys and dolls could provide!
i had tried a lot and finally ended up with solution (Unreliable though).. but works fine..
public static boolean updateCalendar(Context context,String cal_Id,String eventId)
{
try{
Uri CALENDAR_URI = Uri.parse(CAL_URI+"events");
Cursor c = context.getContentResolver().query(CALENDAR_URI, null, null, null, null);
String[] s = c.getColumnNames();
if (c.moveToFirst())
{
while (c.moveToNext())
{
String _id = c.getString(c.getColumnIndex("_id"));
String CalId = c.getString(c.getColumnIndex("calendar_id"));
if ((_id==null) && (CalId == null))
{
return false;
}
else
{
if (_id.equals(eventId) && CalId.equals(cal_Id))
{
Uri uri = ContentUris.withAppendedId(CALENDAR_URI, Integer.parseInt(_id));
context.getContentResolver().update(uri, null, null, null);// need to give your data here
return true;
}
}
}
}
}
finally
{
return true;
}
}
and finally i'm not sure if it works with every device.
Ok, so, the problem was that I was using different URIs between fetching the events and editing them. I used the code sample from here and was using the URI "content://com.android.calendar/instances/when" to fetch the events and display them on the screen. When I had made a change I was using "content://com.android.calendar/events" to edit by id as in my example above.
What I found, thanks to your response, ntc, was that the ids for events between the two URIs were different, and therefore I couldn't edit the events consistently with the information each was giving me. I was presuming the event ids I was getting were system ids and universal to the phone.
I guess I'll have to do some testing and see what hardware isn't compatible with this method. I am using an HTC Evo for testing and so far so good.
When querying the Instances table, use Instances.EVENT_ID to get the identifier for the event you want to edit, instead of Instances._ID.
Related
(first of all, sorry if any of this sounds stupid, but I'm a total nood regarding android)
I'm working on an organizer app where I want to create a Calendar Event using an intend, and afterwards I have to save the events ID in my app so I can open it up again to edit it and so my app can read the events start date.
the code I'm using, I got from this question:
How can I find out the result of my calendar intent?
The intend works but I can't get the rest to work. also, "EventUtility" and "mContext" show up as errors.
p.s. I also get a warning about a missing Permission but I have no idea where to add that
protected void kalender() {
long event_id = EventUtility.getNewEventId(mContext.getContentResolver());
Intent newEvent = new Intent(Intent.ACTION_INSERT)
.setData(CalendarContract.Events.CONTENT_URI)
.putExtra(CalendarContract.Events.TITLE, "Abgabe Termin")
.putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY)
.putExtra(CalendarContract.Events.HAS_ALARM, true)
.putExtra("allDay", true);
startActivity(newEvent);
}
public static long getNewEventId(ContentResolver cr) {
Cursor cursor = cr.query(CalendarContract.Events.CONTENT_URI, new String[]{"MAX(_id) as max_id"}, null, null, "_id");
cursor.moveToFirst();
long max_val = cursor.getLong(cursor.getColumnIndex("max_id"));
return max_val + 1;
}
Part of my functionality requires updating a value in every row (only happens rarely, when a user selects a certain setting).
Trouble is, the query takes a good few minutes to perform (at best), and there's only 269 test records. Is there any way this could be optimized?
String allRecords = "SELECT id, weight FROM Workout_Entry";
Cursor cursor = db.rawQuery(allRecords, null);
int rows = cursor.getCount();
int id;
double weight;
try
{
if (cursor.moveToFirst())
{
do
{
for (int i = 0; i < rows; i++)
{
id = cursor.getInt(0);
weight = cursor.getInt(1) / 2.2;
String strFilter = "id = " + id;
ContentValues args = new ContentValues();
args.put("weight", weight);
db.update("Workout_Entry", args, strFilter, null);
}
} while (cursor.moveToNext());
}
} finally
{
cursor.close();
}
(db).close();
Thanks!
Just push the work to the database engine instead of pulling the data out one row at a time and firing up a new update query each time. Replace your code with something like:
db.execSQL("UPDATE Workout_Entry SET weight=weight/2.2");
Also, since this seems to be some kind of metric/imperial unit conversion, consider keeping the data in just one format in the database and convert/format to the appropriate unit for display purposes.
You should learn to use transactions - you can see example of how you use that in this presentation of mine.
Also showing the impact of not using the transaction.
Ok, I've realised my error. I had a do while loop for every record, and inside of that was a for loop which looped through x many times, where x was the amount of existing records.
So it was going through O(n)² times instead of O(n).
Thanks to those who replied! I found both of your comments useful.
I've been looking everywhere since the past few days to find a way to retrieve a contact name using a phone number I already have stored in a variable, unfortunately everything I found so far seems to be using deprecated functions/calls.
Of Course, I tried doing it my own way but I feel like my Android/JAVA knowledge is not good enough to understand this concept yet, keep getting some errors or force close when I try to run anything.
So far the best thing I could find was something like this:
public String getContactName(final String phoneNumber)
{
Uri uri;
String[] projection;
if (Build.VERSION.SDK_INT >= 5)
{
uri = Uri.parse("content://com.android.contacts/phone_lookup");
projection = new String[] { "display_name" };
}
else
{
uri = Uri.parse("content://contacts/phones/filter");
projection = new String[] { "name" };
}
uri = Uri.withAppendedPath(uri, Uri.encode(phoneNumber));
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
String contactName = "";
if (cursor.moveToFirst())
{
contactName = cursor.getString(0);
}
cursor.close();
cursor = null;
return contactName;
}
But by using this code, Eclipse tells me: context cannot be resolved.
A lot of the codes and explanations I found were using this Context thing, but I still don't understand it even after reading this: What is 'Context' on Android?
Any help will be greatly appreciated,
Thank you very much
If you're using this inside an activity, then a context is what you get by using this. So basically here, instead of calling context.getContentResolver(), call this.getContentResolver() or simply just getContentResolver().
Eclipse complains basically because you're trying to call a method of something called context which Eclipse doesn't know because it hasn't been declared anywhere. It would work if you previously did something like Context context = this;, but that's really useless.
getContentResolver() is a method declared and defined by Activity which is a class that your activity extends, therefore you can call it just like that.
I hope it helps. As to what this context really is, I am sorry, but I can't help you with that as I am not even sure I understand it correctly.
Also, please notice, that I haven't checked the code you posted and I don't know if it works for obtaining a contact's name from a phone number. Just wanted to help you with getting rid of the context cannot be resolved error.
I want to start an activity once i get a missed call.but iam unable to read the latest missed call entry from the call log, instead it reads the entry before the current one. iam reading it when phone state is idle.
Example: say there are two missed call entries one at 11:10 and other at 11:11. I get a missed call at 12:12, my activity needs to show missed calls obtained at 12:12,11:11,11:10. but rather it reads 11:11,11:10. Latest entry is missing. what should i do? I am using a service and reading call log, phone state.
Cursor c = getContentResolver().query(allCalls, null, null, null, order);
if (c.moveToFirst()) {
do{
// getting number,type,ack etc}
while (c.moveToNext()); }
You will need to listen for it using TelephonyManager and PhoneStateListener.
This code will show you how to do it:
if(lastStart == TelephonyManager.CALL_STATE_RINGING)
{
long now = System.currentTimeMillis();
long duration = (now-ringStartTime)/1000;
bindService.AddMissCallInfo(ringPhoneNumber, ringStartTime, duration);
Log.i(Constants.Tag,"service add miss call!");
}
Code taken from: http://code.google.com/p/android-miss-call/source/browse/trunk/src/com/call/DialPhoneStateListener.java?r=3
you can used like this.
c=mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, CallLog.Calls._ID + " DESC");
if(c.getCount()!=0){
c.moveToFirst();
lastCallnumber = c.getString(0);
lastCallnumber=FormatNumber(lastCallnumber);
String type=c.getString(1);
String duration=c.getString(2);
String name=c.getString(3);
String id=c.getString(4);
System.out.println("CALLLLing:"+lastCallnumber+"Type:"+type+"\t id:"+id);
if(type.equals("3")){
//you can get last missedcall here
}
You can try it may be helpful for you.
Someone know if there's a programmatically way to use a specific defined APN on the device which is not the default one?
Thanks.
You can programmatically query and set the preferred APN using the uri content://telephony/carriers/preferapn. To set a new preferred APN you have to pass in the database ID of an existing APN entry. The following function can do this if you pass in the display name of the APN (eg: setPreferredApn(context, "Giffgaff");)
public static final Uri APN_TABLE_URI = Uri.parse("content://telephony/carriers");
public static final Uri APN_PREFER_URI = Uri.parse("content://telephony/carriers/preferapn");
public static boolean setPreferredApn(Context context, String name) {
boolean changed = false;
String columns[] = new String[] { Carriers._ID, Carriers.NAME };
String where = "name = ?";
String wargs[] = new String[] {name};
String sortOrder = null;
Cursor cur = context.getContentResolver().query(APN_TABLE_URI, columns, where, wargs, sortOrder);
if (cur != null) {
if (cur.moveToFirst()) {
ContentValues values = new ContentValues(1);
values.put("apn_id", cur.getLong(0));
if (context.getContentResolver().update(APN_PREFER_URI, values, null, null) == 1)
changed = true;
}
cur.close();
}
return changed;
}
I guess I should add that you need WRITE_APN_SETTINGS permission and need to import android.provider.Telephony and android.provider.Telephony.Carriers
UPDATE FOR 4.0+
This facility became disabled with the release of Android 4.0 (ICS). Enabling the WRITE_APN_SETTINGS permission has no effect on allowing you to set the APN any more. See this question for some relevant links. On the API page it now states explicitly this permission is not for external use and this is enforced internally.
I dont think there is a way, even if there is one, the carrier could wipe it out with a software update. Also, for some carriers like AT&T in US, using a specific APN provides specific functionality, like getting the Subscriber number of that user (its a unique ID, not the phone number). So it may not be a good idea to force this change, as it will impact numerous other apps installed on handset.