Cant get latest item from calllog - android

I have registered an contentobserver monitoring the call log.
But I cant get the latest call, the furthest I came is getting the latest call the first time, after that it just takes the previous and then the previous..
Also it returns 2 log entries at a time.
The code im using is:
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.provider.BaseColumns;
import android.provider.CallLog;
import android.util.Log;
class CallMonitor extends ContentObserver {
private PositionDbAdapter mDbHelper;
Cursor cur;
Context CallMon = Position.MAIN_ACTIVITY;
int idColumn;
int numberColumn;
int dateColumn;
int typeColumn;
int durColumn;
public CallMonitor(Handler handler, Context context){
super(handler);
CallMon = context;
}
#Override
public void onChange(boolean selfChange) {
if(cur==null){
cursorInit(CallMon);
}
if (!cur.moveToNext()) {
//do we really want to close the cursor?
//cur.close();
return;
}
String number = cur.getString(numberColumn);
String id = cur.getString(idColumn);
String type = cur.getString(typeColumn);
String date = cur.getString(dateColumn);
String dur = cur.getString(durColumn);
Date dateN = new Date(Long.parseLong(date));
Date date2 = new Date();
Log.d("Position", date2+": "+dateN+":"+id+", "+number+", "+type+", "+dur);
//cur.moveToNext();
}
public void Destroy() {
Log.d("Position", "Destroy Call Monitor");
cur.close();
}
public void cursorInit(Context context){
String[] projection = new String[]{
BaseColumns._ID,
CallLog.Calls.DATE,
CallLog.Calls.NUMBER,
CallLog.Calls.DURATION,
CallLog.Calls.TYPE
};
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
//cur.moveToFirst();
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
}
}
I've tried various cur.moveToFirst .moveToNext etc...
The closest I came is when it fires the first time, i get the correct callog item, but then i get another one.
Then the second time and third etc.. i get older.
I thought that i i close the cursor then it would start over from the beginning, but when I do this, it throws an error, probably because the cursor is closed when it automatically get the second one, the one i dont want.
So can somebody please help me?

I have done this type of operation but through BroadcastReceiver. may be that will be helpful for you:
public class CallReceiver extends BroadcastReceiver {
//<----------------- Fields------------->
private String phone_no = "";
private int phone_id;
private String incoming_time = "";
private Context context;
#Override
public void onReceive(Context ctx, Intent intent) {
context = ctx;
final Bundle bundle = intent.getExtras();
incomingCalls(bundle);
}
/**
* Check incoming call and match in database
* #param bundle
*/
private void incomingCalls(Bundle bundle) {
if (null == bundle)
return;
Log.i("IncomingCallReceiver", bundle.toString());
final String state = bundle.getString(TelephonyManager.EXTRA_STATE);
Log.i("IncomingCallReceiver", "State: " + state);
phone_no = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)
&& phone_no != null && !phone_no.equalsIgnoreCase("")) {
final DateFormat formatter = new SimpleDateFormat(
"MMM dd yyyy HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
incoming_time = formatter.format(calendar.getTime());
Log.i("IncomingCallReceiver", "Incomng Number: " + phone_no);
if (phone_id != 0) {
Log.i("Phone number", phone_no);
Log.i("Phone ID", phone_id+"");
Log.i("Incoming time", incoming_time);
}
}
}
}

if you want call log to be displayed from older to newer entries
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToNext()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}
and if you want call logs to be displayed from newer to older(i.e latest entry at first)
ContentResolver resolver = context.getContentResolver();
cur.moveToLast()
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToPerivous()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}

Related

Is it possible to add a reminder programatically without creating event in android calendar?

I use Google Calendar Provider for Android to add Events in my Google Calendar:
https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
And this is the example to add Reminder for the Event:
ContentValues values = new ContentValues();
values.put(CalendarContract.Reminders.MINUTES, 15);
values.put(CalendarContract.Reminders.EVENT_ID, reminderEventId);
values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, values);
But in my Google Calendar app I can create Reminders without having EVENT_ID. Is it possible to create the same reminders with Google Calendar Provider for Android?
The same like this:
https://gsuiteupdates.googleblog.com/2016/04/launch-of-reminders-for-google-calendar.html
I have see that Google launch reminders for Google Calendar 2016 (This is a different Reminders from Event Reminders) and at the moment I can`t find in Android SDK (API 25) this kind of Google Calendar Reminders (and possibility to add programmatically appointment slots too).
A tricky approach I'm using is creating the remainders, instead of calendar, in the contacts, using Custom Reminder (and the ContactContract provider). So, you can use any label, and the reminder is shown in the specific date.
Cons:
- You have to have the "Birthday" calendar enable
- The remainder is date based (not time)
- They don't repeat the reminder (as the new calendar does)
package es.goodsal.mobile.provider.contact;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.provider.ContactsContract.CommonDataKinds.Event;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import es.goodsal.mobile.app.App;
import es.goodsal.mobile.model.ReminderType;
/**
* Created by jmalbarran on 16/9/17.
*/
public class Reminder implements Comparable<Reminder> {
private static final String TAG = Reminder.class.getSimpleName();
private static final SimpleDateFormat fullPeriodicDateFormat = new SimpleDateFormat("--MM-dd");
private static final SimpleDateFormat periodicDateFormat = new SimpleDateFormat("MM-dd");
private static final SimpleDateFormat nonPeriodicDateFormat = new SimpleDateFormat("yyyy-MM-dd");
private static final String DUE_DATE = Event.DATA4;
private static final String COMMENT = Event.DATA5;
private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI;
private static final String[] PROJECTION = new String[]{
Event._ID, //0
Event.CONTACT_ID, //1
Event.LOOKUP_KEY, //2
Event.START_DATE, //3
Event.TYPE, //4
Event.LABEL, //5 Label for custom event
Reminder.DUE_DATE, // 6
Reminder.COMMENT // 7 Use this field to save Comments
};
static {
periodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
nonPeriodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
}
private long id = -1;
private ConContact contact;
private Date reminderDate;
private Date dueDate;
private ReminderType type;
private String comment;
// region Constructor
public Reminder(ConContact contact, Date reminderDate,
Date dueDate, ReminderType type, String comment) {
this.contact = contact;
this.reminderDate = reminderDate;
this.dueDate = dueDate;
this.type = type;
this.comment = comment;
}
public Reminder(#NonNull String reminderUri) {
this(Uri.parse(reminderUri));
}
public Reminder(#NonNull Uri reminderUri) {
Cursor cursor;
cursor = App.getContentResolverInstance().query(reminderUri,
PROJECTION, null, null, null);
if (cursor == null) {
throw new IllegalArgumentException(reminderUri.toString() + " opportunity not found.");
} else {
cursor.moveToFirst();
setFromCursor(null, cursor);
}
}
private Reminder(#NonNull Cursor cursor) {
this(null, cursor);
}
private Reminder(#Nullable ConContact contact, #NonNull Cursor cursor) {
setFromCursor(contact, cursor);
}
private void setFromCursor(#Nullable ConContact contact, #NonNull Cursor cursor) {
int eventType;
String eventLabel;
Calendar calDueDate, calReminderDate;
Date now;
String strSplitDate[];
String strDueDate;
this.id = cursor.getLong(0);
if (contact != null) {
this.contact = contact;
} else {
this.contact = new ConContact(cursor.getLong(1), cursor.getString(2));
}
// Type
eventType = cursor.getInt(4); //Event.TYPE
eventLabel = cursor.getString(5); //Event.LABEL
switch (eventType) {
case ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY:
type = ReminderType.anniversary;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY:
type = ReminderType.birthday;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM:
type = ReminderType.other;
eventLabel = cursor.getString(5);
for (ReminderType iType : ReminderType.values()) {
if (iType.getLabel().equals(eventLabel)) {
type = iType;
break;
}
}
break;
default:
type = ReminderType.other;
}
// Due / Reminder date
try {
now = new Date();
if (type.isPeriodic()) {
// Periodic Due date
calDueDate = Calendar.getInstance();
calDueDate.setTime(now);
strSplitDate = cursor.getString(6).split("-"); // DATA4
if (strSplitDate != null && strSplitDate.length == 3) {
calDueDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calDueDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calDueDate.before(now)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, 1); // Next year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder due date " +
cursor.getString(6));
}
dueDate = calDueDate.getTime();
// Periodic Reminder date
calReminderDate = Calendar.getInstance();
calReminderDate.setTime(dueDate);
strSplitDate = cursor.getString(3).split("-"); // START_DATE
if (strSplitDate != null && strSplitDate.length == 3) {
calReminderDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calReminderDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calReminderDate.after(dueDate)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, -11); // Previous year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder start date " +
cursor.getString(6));
}
reminderDate = calReminderDate.getTime();
} else {
// Non periodic date
reminderDate = nonPeriodicDateFormat.parse(cursor.getString(3)); // START_DATE
dueDate = nonPeriodicDateFormat.parse(cursor.getString(6)); // DATA4
dueDate = dueDate !=null ? dueDate : reminderDate;
}
} catch (Exception e) { // NullPointer and/or ParseFormat
dueDate = null;
reminderDate = null;
}
// Comment
comment = cursor.getString(7); // DATA5
}
// endregion Constructor
// region Getter/Setter
public Uri getUri() {
Uri uri;
uri = null;
if (id != -1) {
uri = ContentUris.withAppendedId(CONTENT_URI, id);
}
return uri;
}
public ConContact getContact() {
return contact;
}
public Date getReminderDate() {
return reminderDate;
}
public Date getDueDate() {
return dueDate;
}
public ReminderType getReminderType() {
return type;
}
public String getComment() {
return comment;
}
public boolean isPeriodic() {
return type.isPeriodic();
}
public void setContact(ConContact contact) {
this.contact = contact;
}
public void setReminderDate(Date reminderDate) {
this.reminderDate = reminderDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public void setType(ReminderType type) {
this.type = type;
}
public void setComment(String comment) {
this.comment = comment;
}
// endregion Getter/Setter
// region Commands
public boolean save() {
boolean ret;
ContentValues values;
Uri savedUri;
ret = false;
values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.Event.MIMETYPE,
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
//values.put(ContactsContract.CommonDataKinds.Event.CONTACT_ID, contact.getContactId());
values.put(ContactsContract.CommonDataKinds.Event.RAW_CONTACT_ID, contact.getRawContactId());
if (type.isPeriodic()) {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
fullPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
fullPeriodicDateFormat.format(dueDate));
} else {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
nonPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
nonPeriodicDateFormat.format(dueDate));
}
values.put(ContactsContract.CommonDataKinds.Event.TYPE,
Integer.toString(type.getContactEventType()));
values.put(ContactsContract.CommonDataKinds.Event.LABEL, type.getLabel());
values.put(ContactsContract.CommonDataKinds.Event.DATA5, comment);
if (id == -1L) {
// Create new
savedUri = App.getContentResolverInstance().insert(ContactsContract.Data.CONTENT_URI, values);
id = ContentUris.parseId(savedUri);
ret = true;
Log.d(TAG, "save: Inserted uri=" + savedUri + " id=" + id);
} else {
// update existing id
// if (0<App.getContentResolverInstance().update(ContactsContract.Data.CONTENT_URI, values,
// ContactsContract.Data._ID + "='" + Long.toString(id) + "'", null)){
if (0 < App.getContentResolverInstance().update(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
values,
null,
null)) {
ret = true;
Log.d(TAG, "save: Updated id=" + id);
} else {
Log.e(TAG, "save: Error updating id=" + id);
}
}
contact.resetReminders();
return ret;
}
public boolean delete() {
boolean ret = false;
if (id != -1) {
if (0 < App.getContentResolverInstance().delete(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
null,
null)) {
Log.d(TAG, "delete: Deleted id=" + id);
ret = true;
} else {
Log.w(TAG, "delete: Not found id=" + id);
}
}
return ret;
}
// endregion Commands
#Override
public int compareTo(#NonNull Reminder o) {
if (reminderDate == null) {
return 1; // null always at end
} else {
if (o.reminderDate == null) {
return -1;
} else {
return reminderDate.compareTo(o.reminderDate);
}
}
}
/**
* Get reminders for all contact, in a specific date (including periodics)
*
* #param date exact to search for (reminder date NOT due date)
* #return List of reminders
*/
public static List<Reminder> getReminders(Date date) {
Cursor cursor;
ArrayList<Reminder> retList;
String where;
String[] selectionArgs;
Date dueDate;
String dateSelection;
String[] strSplitDate;
Calendar calDueDate;
retList = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String sortOrder = null;
// Execute one query per reminder type
for (ReminderType type : ReminderType.values()) {
dateSelection = type.isPeriodic() ?
"%" + periodicDateFormat.format(date) :
"%" + nonPeriodicDateFormat.format(date);
if (type.getContactEventType() == ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM) {
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.LABEL + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection,
type.getLabel()
};
} else {
// Non custom reminder. Don't check label
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection
};
} // where & selection per event type
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(cursor));
}
cursor.close();
} // if cursor
} // for per every type
return retList;
}
/**
* Get reminders for a specific contact, from a date forward
*
* #param contact Contact for search for
* #param date current or future date to search (including periodic)
* #return List of reminders for current or future search
*/
public static List<Reminder> getReminders(ConContact contact, Date date) {
Uri uri;
Cursor cursor;
ArrayList<Reminder> retList = null;
String where;
String[] selectionArgs;
String sortOrder;
int contactEventType;
String label;
Calendar calReminderDate, calDueDate;
String strReminderDate, strDueDate;
ReminderType type;
Date reminderDate;
Date dueDate;
String strDescription;
String[] strSplitDate;
uri = ContactsContract.Data.CONTENT_URI;
sortOrder = null;
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + " = ? AND " +
ContactsContract.CommonDataKinds.Event.CONTACT_ID + " = ? AND " +
"(" +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE '--%' OR " +
ContactsContract.CommonDataKinds.Event.START_DATE + " >= ?" +
")";
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
Long.toString(contact.getContactId()),
nonPeriodicDateFormat.format(date)
};
sortOrder = ContactsContract.CommonDataKinds.Event.START_DATE;
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(contact, cursor));
}
Collections.sort(retList);
cursor.close();
} // if cursor
// for per every type
return retList;
}
} // end Reminder class
As stated in https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
Reminders are specified in minutes before the event and have a method
that determines how the user will be alerted.
A reminder that doesn't belong to an event will not have a time of reference to go off.
I think for what you are trying to achieve () it would be best for you to look at Androids AlarmManager https://developer.android.com/reference/android/app/AlarmManager.html
Or see what other people are saying about similar things https://stackoverflow.com/a/16549111/6431430

Read events from android calendar

I have a little problem with my code .I use Android Studio .
I try to make an application to the phone's calendar events displaying time . I don't have any errors but when I tried to run it to my phone
Caused by:
java.lang.NullPointerException
at net.jimblackler.readcalendar.Example.readCalendar(Example.java:29)
at net.jimblackler.readcalendar.MainActivity.onCreate(MainActivity.java:14)
Here is my cod :
Java Class:
import java.util.Date;
import java.util.HashSet;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.text.format.DateUtils;
public class Example {
public static void readCalendar(Context context) {
ContentResolver contentResolver = context.getContentResolver();
// Fetch a list of all calendars synced with the device, their display names and whether the
// user has them selected for display.
final Cursor cursor = contentResolver.query(Uri.parse("content://calendar/calendars"),
(new String[] { "_id", "displayName", "selected" }), null, null, null);
HashSet<String> calendarIds = new HashSet<String>();
while (cursor.moveToNext()) {
final String _id = cursor.getString(0);
final String displayName = cursor.getString(1);
final Boolean selected = !cursor.getString(2).equals("0");
System.out.println("Id: " + _id + " Display Name: " + displayName + " Selected: " + selected);
calendarIds.add(_id);
}
// For each calendar, display all the events from the previous week to the end of next week.
for (String id : calendarIds) {
Uri.Builder builder = Uri.parse("content://calendar/instances/when").buildUpon();
long now = new Date().getTime();
ContentUris.appendId(builder, now - DateUtils.WEEK_IN_MILLIS);
ContentUris.appendId(builder, now + DateUtils.WEEK_IN_MILLIS);
Cursor eventCursor = contentResolver.query(builder.build(),
new String[] { "title", "begin", "end", "allDay"}, "Calendars._id=" + id,
null, "startDay ASC, startMinute ASC");
while (eventCursor.moveToNext()) {
final String title = eventCursor.getString(0);
final Date begin = new Date(eventCursor.getLong(1));
final Date end = new Date(eventCursor.getLong(2));
final Boolean allDay = !eventCursor.getString(3).equals("0");
System.out.println("Title: " + title + " Begin: " + begin + " End: " + end +
" All Day: " + allDay);
}
}
}
}
MainActivity:
package net.jimblackler.readcalendar;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Example.readCalendar(this);
}
}
First, please check the uri address . For example 'content://calendar/calendars' , it's not used over Android 2.1.
Before Android 14:
calanderURL = "content://calendar/calendars";
calanderEventURL = "content://calendar/events";
calanderRemiderURL= "content://calendar/reminders";
After:
calanderURL = "content://com.android.calendar/calendars";
calanderEventURL = "content://com.android.calendar/events";
calanderRemiderURL = "content://com.android.calendar/reminders";
However, you'd better use like this:
private Uri calendarsUri = Calendars.CONTENT_URI;
private Uri eventsUri = Events.CONTENT_URI;
private Uri remindersUri = Reminders.CONTENT_URI;
private Uri attendeesUri = Attendees.CONTENT_URI;
Second , please check the table column name . You can print the following columns and have a look .
/** Calendars table columns */
public static final String[] CALENDARS_COLUMNS = new String[] {
Calendars._ID, // 0
Calendars.ACCOUNT_NAME, // 1
Calendars.CALENDAR_DISPLAY_NAME, // 2
Calendars.OWNER_ACCOUNT // 3
};
/** Events table columns */
public static final String[] EVENTS_COLUMNS = new String[] {
Events._ID,
Events.CALENDAR_ID,
Events.TITLE,
Events.DESCRIPTION,
Events.EVENT_LOCATION,
Events.DTSTART,
Events.DTEND,
Events.EVENT_TIMEZONE,
Events.HAS_ALARM,
Events.ALL_DAY,
Events.AVAILABILITY,
Events.ACCESS_LEVEL,
Events.STATUS,
};
/** Reminders table columns */
public static final String[] REMINDERS_COLUMNS = new String[] {
Reminders._ID,
Reminders.EVENT_ID,
Reminders.MINUTES,
Reminders.METHOD,
};
/** Reminders table columns */
public static final String[] ATTENDEES_COLUMNS = new String[] {
Attendees._ID,
Attendees.ATTENDEE_NAME,
Attendees.ATTENDEE_EMAIL,
Attendees.ATTENDEE_STATUS
};
Third, you code manner is very bad .You should declare these above parameters as 'static final' ones .

Android browser history URI?

I need to save the last visited webpage by user.
Evething works fine with my Galaxy S4 (5.0.1) with Chrome Browser.
However, on some phones I got nothing or very mixed results. From what I gathered, the biggest problem is with Browser URI itself. Some phones use Chrome as their main browser, some use something else.
I have three sources:
content://com.android.chrome.browser/bookmarks
content://com.sec.android.app.sbrowser/bookmarks
Browser.BOOKMARKS_URI
So right now I'm working on something like this:
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
h.removeCallbacks(this);
h.postDelayed(this, 500);
}
public void run() {
String[] proj = new String[] { Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL,Browser.BookmarkColumns.DATE };
String selection = Browser.BookmarkColumns.BOOKMARK + " = 0"; // 0 = history, 1 = bookmark
Cursor mCur = null;
try {
mCur = contentResolver.query(getURI(), proj, selection, null, null);
if(mCur != null && mCur.moveToLast()){
String title = "";
String url = "";
title = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.URL));
...
}
} catch (Exception e){
...
} finally {
if(mCur != null)
mCur.close();
}
}
private Uri getURI(){
Uri uri = Uri.parse("content://com.android.chrome.browser/bookmarks");
return uri;
}
Whet is the best way to provide correct URI?
onChange is triggered as content observer on browsers history.
So user can browse internet on Chrome and I still get history results from ASOP browser.
When I observe chrome directly, on some phones I get failed to find provider info, because there is no chrome installed.
What are other "popular" sources to search for browser history? I'd prefer to make this as bulletproof as possible.
try it: (run perfectly in android > 4.0 and 5 or 6.0 ); Anything, create a contentObserver array in FOREACH and add a list and record a different URI for each.
in service android (background):
HistoryObserver hObserver;
public void onCreate() {
hObserver = new HistoryObserver(new Handler(), this);
getApplicationContext().getContentResolver().registerContentObserver(Uri.parse("content://com.android.chrome.browser/history"), true, hObserver);
}
Class historicObserver:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.provider.Browser;
import android.util.Log;
public class HistoryObserver extends ContentObserver {
public final String TAG = "HistoryObserver";
Context context;
public HistoryObserver(Handler handler, Context c) {
super(handler);
Log.d(TAG, "Creating new HistoryObserver");
context = c;
}
public HistoryObserver(Context c) {
super(null);
Log.d(TAG, "Creating a new HistoryObserver without a Handler");
context = c;
}
#Override
public boolean deliverSelfNotifications() {
Log.d(TAG, "delivering self notifications");
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "onChange without uri: " + selfChange);
// onChange(selfChange, null);
}
#SuppressLint("NewApi")
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d(TAG, "onChange: " + selfChange + "\t " + uri.toString());
String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL, Browser.BookmarkColumns.DATE };
String selection = Browser.BookmarkColumns.BOOKMARK + " = 0"; // 0 =
// history,
// 1 =
// bookmark
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Cursor mCursor = context.getContentResolver().query(Browser.BOOKMARKS_URI,
proj, selection, null, null);
// this.startManagingCursor(mCursor);
mCursor.moveToFirst();
int count = mCursor.getColumnCount();
String COUNT = String.valueOf(count);
Log.e("Browser sayac", COUNT);
String title = "";
String url = "";
String date = "";
if (mCursor.moveToFirst() && mCursor.getCount() > 0) {
while (mCursor.isAfterLast() == false) {
title = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.URL));
date = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.DATE));
Long timestamp = Long.parseLong(date);
SimpleDateFormat dateFormat = new SimpleDateFormat(
"dd/MM/yyyy/HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
String finaldate = dateFormat.format(calendar.getTime());
String smsDate = finaldate.toString();
// Log.e("DTE", date);
Log.e("URL", title);
Log.e("TARIH", smsDate);
mCursor.moveToNext();
}
}
}
}

Is there an standard way to access calendar events, call logs and inbox messages?

I've developed an application that accesses calendar events, call logs and inbox messages by using things like this:
cursor = this.contentResolver.query(CallLog.Calls.CONTENT_URI, projection, selection, null, order);
The app works perfectly in Galaxy SII but when I installed it in XPeria U it don't worked, probably because that phone manages calendars, calls and messages in a different way.
If I have to develop an application to each phone in the world, this is not a good business. I tried some Android classes like CalendarContract.Events but its API level is too hard and I don't want that because it won't work in most phones. Is there a good standard way to tho this that works on a high number of devices?
Thanks!
package bembibre.coolstar.windowsmobilewidget.backend;
import java.util.ArrayList;
import java.util.List;
import bembibre.coolstar.windowsmobilewidget.apiindependent.ApiIndependentCallLog;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.CallLog;
import android.util.Log;
public class CallsContentResolver {
public static final String[] projection = {
CallLog.Calls.CACHED_NAME,
CallLog.Calls.DATE,
};
public static final String selection = "((" + CallLog.Calls.TYPE + " = " +
CallLog.Calls.MISSED_TYPE + ") AND NOT(" +
ApiIndependentCallLog.instance().CALLS_IS_READ + "))";
private static final int MAX_NUM_CALLS = 3;
private static final String order = CallLog.Calls.DATE + " DESC LIMIT " + MAX_NUM_CALLS;
private ContentResolver contentResolver;
public CallsContentResolver(Context ctx) {
this.contentResolver = ctx.getContentResolver();
}
public void readCursor(List<Call> calls, Cursor cursor){
while (cursor.moveToNext()) {
String cached_name = cursor.getString(cursor.getColumnIndex(
CallLog.Calls.CACHED_NAME)
);
long date = cursor.getLong(cursor.getColumnIndex(
CallLog.Calls.DATE)
);
Call call = new Call(cached_name, date);
calls.add(0, call);
}
}
public List<Call> getMissedCalls(){
List<Call> calls = new ArrayList<Call>();
Cursor cursor = null;
try{
cursor = this.contentResolver.query(CallLog.Calls.CONTENT_URI, projection, selection, null, order);
if(cursor.getCount() > 0) {
this.readCursor(calls, cursor);
}
}
catch(Exception e){
Log.d("EXCEPCIÓN", e.getMessage());
}
finally{
if(cursor != null){
cursor.close();
}
}
return calls;
}
}
have a look at Calendar Provider (http://developer.android.com/guide/topics/providers/calendar-provider.html) and Contacts Provider (http://developer.android.com/guide/topics/providers/contacts-provider.html).
You can fetch the calender event from this query where
long after = date.getTime();
long current = new Date().getTime();
long millisOfOne = 1000;
long millisOftwoFour = 1000 * 60 * 60 * 24;
long millisOfTodayLast = date.getTime() + millisOftwoFour
- millisOfOne;
Cursor cursor = context.getContentResolver().query(Uri.parse("content://com.android.calendar/events"),new String[] { "calendar_id", "title", "description","dtstart", "dtend", "eventLocation", "_id" },"dtstart >=" + after + " and dtstart<" + millisOfTodayLast,
null, "dtstart ASC");

ContentObserver onChange() repeats multiple times

I'm trying to query the data from the CallLog and insert in DB. For that, I've created a COntentObserver as inner class in a Service, and inside onChange() method, I call my method that goes to the specified URI and query the data that has changed.
But, lets say, I received a call, so the observer was notified. So, my method goes to the call log content provider, query and insert, but it is inserting two, three times the same register.
Here is the code of my service.
public class RatedCallsService extends Service
private Handler handler = new Handler();
private SQLiteDatabase db;
private OpenHelper helper;
private String theDate;
private String theMonth_;
private String theYear_;
private String theDay_;
public static boolean servReg = false;
class RatedCallsContentObserver extends ContentObserver {
public RatedCallsContentObserver(Handler h) {
super(h);
//helper = new OpenHelper(getApplicationContext());
//db = helper.getWritableDatabase();
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(LOG_TAG, "Inside on Change. selfChange " + selfChange);
searchInsert();
}
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
servReg = true;
db = DataHandlerDB.createDB(this);
registerContentObserver();
}
#Override
public void onDestroy() {
super.onDestroy();
db.close();
this.getApplicationContext().getContentResolver().unregisterContentObserver(new RatedCallsContentObserver(handler));
}
private void searchInsert() {
Cursor cursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, null, null, null,
android.provider.CallLog.Calls.DATE + " DESC ");
if (cursor.moveToFirst()) {
int numberColumnId = cursor
.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
int durationId = cursor
.getColumnIndex(android.provider.CallLog.Calls.DURATION);
int contactNameId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);
int numTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE);
int callTypeId = cursor
.getColumnIndex(android.provider.CallLog.Calls.TYPE);
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String currTime = hours + ":" + minutes + ":" + seconds;
SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/yyyy");
Date date = new Date();
cursor.moveToFirst();
String contactNumber = cursor.getString(numberColumnId);
String contactName = (null == cursor.getString(contactNameId) ? ""
: cursor.getString(contactNameId));
String duration = cursor.getString(durationId);
String numType = cursor.getString(numTypeId);
String callType = cursor.getString(callTypeId);
seconds = Integer.parseInt(duration);
theDate = dateFormat.format(date);
if (theDate.length() == 9) {
theMonth_ = theDate.substring(0, 1);
theDay_ = theDate.substring(2, 4);
theYear_ = theDate.substring(5, 9);
} else if (theDate.length() == 10) {
theMonth_ = theDate.substring(0, 2);
theDay_ = theDate.substring(3, 4);
theYear_ = theDate.substring(6, 10);
} else if (theDate.length() == 8) {
theMonth_ = theDate.substring(0, 1);
theDay_ = theDate.substring(2, 3);
theYear_ = theDate.substring(4, 8);
}
ContentValues values = new ContentValues();
ContentValues values2 = new ContentValues();
values.put("contact_id", 1);
values.put("contact_name", contactName);
values.put("number_type", numType);
values.put("contact_number", contactNumber);
values.put("duration", Utilities.convertTime(seconds));
values.put("date", dateFormat.format(date));
values.put("current_time", currTime);
values.put("cont", 1);
values.put("type", callType);
values2.put("month",
Utilities.monthName(Integer.parseInt(theMonth_)));
values2.put("duration", Utilities.convertTime(seconds));
values2.put("year", theYear_);
values2.put("month_num", Integer.parseInt(theMonth_));
if (!db.isOpen()) {
db = getApplicationContext()
.openOrCreateDatabase(
"/data/data/com.project.myapp/databases/myDb.db",
SQLiteDatabase.OPEN_READWRITE, null);
}
if (duration != "") {
if (Integer.parseInt(duration) != 0) {
String existingMonthDuration = DataHandlerDB
.selectMonthsDuration(theMonth_, theYear_, this);
Integer newMonthDuration;
if (existingMonthDuration != "") {
newMonthDuration = Integer
.parseInt(existingMonthDuration)
+ Integer.parseInt(duration);
values2.put("duration",
Utilities.convertTime(newMonthDuration));
db.update(DataHandlerDB.TABLE_NAME_3, values2,
"year = ?", new String[] { theYear_ });
} else {
db.insert(DataHandlerDB.TABLE_NAME_3, null, values2);
}
db.insert(DataHandlerDB.TABLE_NAME_2, null, values);
}
}
cursor.close();
}
}
public void registerContentObserver() {
this.getApplicationContext()
.getContentResolver()
.registerContentObserver(
android.provider.CallLog.Calls.CONTENT_URI, false,
new RatedCallsContentObserver(handler));
}
}
I've tried everything. unregistering the observer, etc. but nothing.
I selected the timestamp of the call from android.provider.CallLog.Calls.DATE and before I insert I check if there is some timestamp like that one, if there is I dont insert, if there isnt I insert the data. This values are unique, so never will have some like each other.
This happens to me when I suscribe tot he SMS content provider. I think is they way Android handles messages and calls that makes this behavior, I get the call 2 times whenever I send an SMS so I'm guessing is due to the message being put in the outbox table ? first, and then moved to the sent table. Perhaps something similar happens with the calls provider? Maybe this call is placed to a temporary table inside the provider and then once you receive it or miss it this call goes to the proper table (received/missed). What I do is, I check the Id of the message everytime my observer gets called and I keep the Id of the previous message so I can check If the observer is being calld due to the same ID I just handled.
does the selfChange vary ?
Hint. do not rely on this provider to monitor all your calls. Once android decides to terminate your application you will notice that your provider won't receive anymore calls. Try to schedule the attachment of the content observer every once in a while using AlarmManager.

Categories

Resources