Get events from public google calendar Android - android

I would like to have a calendar view that would present all of the events of a public google calendar.
I have an OAuth 2.0 client ID for my user and my calendar is set to PUBLIC.
Then I went trough the Calendar Provider tutorial (https://developer.android.com/guide/topics/providers/calendar-provider.html) and use this code:
public class MainActivity extends Activity {
// Projection array. Creating indices for this array instead of doing
// dynamic lookups improves performance.
public static final String[] EVENT_PROJECTION = new String[]{
CalendarContract.Calendars._ID, // 0
CalendarContract.Calendars.ACCOUNT_NAME, // 1
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, // 2
CalendarContract.Calendars.OWNER_ACCOUNT // 3
};
// The indices for the projection array above.
private static final int PROJECTION_ID_INDEX = 0;
private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Run query
Cursor cur = null;
ContentResolver cr = getContentResolver();
Uri uri = CalendarContract.Calendars.CONTENT_URI;
String selection = "((" + CalendarContract.Calendars.ACCOUNT_NAME + " = ?) AND ("
+ CalendarContract.Calendars.ACCOUNT_TYPE + " = ?) AND ("
+ CalendarContract.Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[]{"****#gmail.com", "google.com",
"****#gmail.com"};
// Submit the query and get a Cursor object back.
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
// Use the cursor to step through the returned records
while (cur.moveToNext()) {
long calID = 0;
String displayName = null;
String accountName = null;
String ownerName = null;
// Get the field values
calID = cur.getLong(PROJECTION_ID_INDEX);
displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
}
}
}
Unfortunately, the Cursor stayed empty. I was also trying to define the ACCOUNT_TYPE to "LOCAL", but it didn't work.
Target SDK set to 21, and i have all the necessary permissions.
How can I retrieve the events of my calendar? Please help /:

Related

"Attempted to access a cursor after it has been closed"

I cannot understand this problem. I have tried to get the solution from other stackoverflow questions but failed to get the solution. I was not getting this error before. However, now I don't know what's wrong with the code stated below. Please help me with this. I'm stuck with this problem.
public void getAlbumsLists() {
final Uri uri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
final String _id = MediaStore.Audio.Albums._ID;
final String album = MediaStore.Audio.Media.ALBUM;
final String album_name = MediaStore.Audio.AlbumColumns.ALBUM;
final String artist = MediaStore.Audio.AlbumColumns.ARTIST;
final String tracks = MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS;
// final String data=MediaStore.Audio.Albums.ALBUM_ID; // NO
// final String id1=MediaStore.Audio.Albums.ALBUM_ID;
final String tit = MediaStore.Audio.Albums.ALBUM; //NO
final String nam = MediaStore.Audio.Albums.ALBUM_KEY; // NO
final String typ = MediaStore.Audio.Media.MIME_TYPE; // NO
final String art = MediaStore.Audio.Albums.ALBUM_ART; //<<<< CAN GET
final String artstkey = MediaStore.Audio.Artists.ARTIST_KEY; //<<<< CAN GET
final String frstyr = MediaStore.Audio.AlbumColumns.FIRST_YEAR; //<<<< CAN GET
final String lstyr = MediaStore.Audio.AlbumColumns.LAST_YEAR; //<<<< CAN GET
final String artstid = "artist_id"; //<<<< CAN GET
final String[] columns = {"*"};
Cursor cursor = getActivity().getContentResolver().query(uri, columns, null, null, null);
// Lists the columns in the cursor
for (String s : cursor.getColumnNames()) {
Log.d("COLUMNS", "Column = " + s);
}
while (cursor.moveToNext()) {
String id = (cursor.getString(cursor.getColumnIndex(_id)));
String name = cursor.getString(cursor.getColumnIndex(album_name));
String artist2 = cursor.getString(cursor.getColumnIndex(artist));
String nr = cursor.getString(cursor.getColumnIndex(tracks));
String x = (cursor.getString(cursor.getColumnIndex(album)));
//String data1=cursor.getString(cursor.getColumnIndexOrThrow(data)); //<<<< NOT A COLUMN
// String id2=cursor.getString(cursor.getColumnIndex(data));
//String title=cursor.getString(cursor.getColumnIndex(tit)); //<<<< NOT A COLUMN
//String name1=cursor.getString(cursor.getColumnIndex(nam)); //<<<< NOT A COLUMN
//String type=cursor.getString(cursor.getColumnIndex(typ)); //<<<< NOT A COLUMN
// AVAIALABLE COLUMNS
String artwork = cursor.getString(cursor.getColumnIndex(art)); //<<<< ADDED
String artistkey = cursor.getString(cursor.getColumnIndex(artstkey)); //<<<< ADDED
String artistid = cursor.getString(cursor.getColumnIndex(artstid)); //<<<< ADDED
String minyear = cursor.getString(cursor.getColumnIndex(frstyr));
String maxyear = cursor.getString(cursor.getColumnIndex(lstyr));
s = new albumInfo(id, name, artist2, nr, artwork, x); // EXCLUDED
albumList.add(s);
cursor.close();
recyclerView1.setAdapter(albumAdapter); // EXCLUDED
}
}
Move cursor.close(); outside the while loop.
Edited..
First time after the while loop iterates the cursor is closed so you need to put it outside while.
I can suggest three improvement scenarios.
You need to move the cursor to first before accessing it for fetching data from the cursor.
You need to close the cursor when nothing is returned or the cursor is null.
Move the cursor close outside of your while loop.
So I would like to recommend you to rewrite the code like following.
// After you have fetched the data from cursor
if(cursor == null) return;
if(cursor.size() == 0) {
cursor.close();
return;
}
for (String s : cursor.getColumnNames()) {
Log.d("COLUMNS", "Column = " + s);
}
// Move the cursor to the first position.
cursor.moveToFirst();
do {
String id = (cursor.getString(cursor.getColumnIndex(_id)));
String name = cursor.getString(cursor.getColumnIndex(album_name));
String artist2 = cursor.getString(cursor.getColumnIndex(artist));
String nr = cursor.getString(cursor.getColumnIndex(tracks));
String x = (cursor.getString(cursor.getColumnIndex(album)));
// ... Other code
} while (cursor.moveToNext());
recyclerView1.setAdapter(albumAdapter); // EXCLUDED
// Move the cursor outside of while loop
cursor.close();

RxJava: Reduce or Combine or Merge

What I want to do is query the Android ContentProvider for Contacts.
The Cursor returns contains multiple duplicates for a contact where they may have more than one number registered against their contact_id)
So far, I have queried the DB, and am iterating through the Cursor rows.
I map() these rows and converting them into a ValueObjects
Next I want to go through all the list of VO’s and merge the ones that have the same contact_id (the VO would store an array of label & numbers)
But, I am stuck, I can not figure out how to perform the last part, how can I loop through the list of ValueObjects, merging the duplicates into one and then disposing the unneeded ones.
This is a sample of the Cursor returned by the ContentProvider:
86 {
_id=5190
contact_id=2167
display_name=John Doe
data1=+44 20 7123 7890
data2=3
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
87 {
_id=5191
contact_id=2167
display_name=John Doe
data1=+44 7967 123 789
data2=2
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
88 {
_id=5192
contact_id=2167
display_name=John Doe
data1=+44 208 123 7890
data2=1
data3=null
photo_thumb_uri=content://com.android.contacts/contacts/2167/photo
lookup=731i7g4b3e9879f40515
}
Sample of the function
public static Observable<List<ContactVO>> fetchAllContacts(final Context context) {
allContactsQuery(context);
return ContentObservable.fromCursor(allContactsQuery(context))
.map(mapToContactVO())
.toList()
// I am stuck
}
private static Cursor allContactsQuery(Context context) {
final String[] CONTACTS = new String[]{
Phone._ID, //.....0
Phone.CONTACT_ID, //.....1
Contacts.DISPLAY_NAME_PRIMARY, //.....2
Phone.NUMBER, //.....3
Phone.TYPE, //.....4
Phone.LABEL, //.....5
Contacts.PHOTO_THUMBNAIL_URI, //.....6
Contacts.LOOKUP_KEY, //.....7
};
String SELECTION = Contacts.DISPLAY_NAME_PRIMARY +
"<>''" + " AND " + Contacts.IN_VISIBLE_GROUP + "=1" +
" AND " + Contacts.HAS_PHONE_NUMBER + "=1";
final String[] SELECTION_ARGS = null;
final String SORT_ORDER = Contacts.SORT_KEY_PRIMARY;
Cursor cursor = context.getContentResolver().query(
Phone.CONTENT_URI,
CONTACTS,
SELECTION,
SELECTION_ARGS,
SORT_ORDER);
return cursor;
}
#NonNull
private static Func1<Cursor, ContactVO> mapToContactVO() {
return cursor -> {
int len = cursor.getCount();
final ContactVO contact = new ContactVO();
contact.contactId = cursor.getString(CONTACT_ID);
contact.displayName = cursor.getString(DISPLAY_NAME);
contact.photoThumbnailUri = cursor.getString(PHOTO_THUMBNAIL_URI);
contact.lookUp = cursor.getString(LOOK_UP);
contact.addData(
new Pair<String, String>(
cursor.getString(PHONE_TYPE),
cursor.getString(PHONE_NUMBER)
)
);
return contact;
};
}
public final static int CONTACT_ID = 1;
public final static int DISPLAY_NAME = 2;
public final static int PHONE_NUMBER = 3;
public final static int PHONE_TYPE = 4;
public final static int PHONE_LABEL = 5;
public final static int PHOTO_THUMBNAIL_URI = 6;
public final static int LOOK_UP = 7;
Use groupBy to get the records with the same contactId together then flatMap and reduce to merge the records
ContentObservable.fromCursor(allContactsQuery(context))
.map(mapToContactVO())
.groupBy(contact -> contact.contactId)
.flatMap(g -> g.reduce(mergeContacts()));

Account Name in Calendar Android getting gmail automatically

I found this article very useful http://developer.android.com/guide/topics/providers/calendar-provider.html#query?
But here i found the ACCOUNT_NAME queried in the calendar is being written statically
I am stuck here Since my problem is ..what if i want user's gmail address through some query
i.e not statically specifying the address rather getting it through some code
PS: i am very newbie to android. Apologies if this ones a stupid question
long calID = 0;
String displayName = null;
String accountName = null;
String ownerName = null;
final String[] EVENT_PROJECTION = new String[] {
Calendars._ID, // 0
Calendars.ACCOUNT_NAME, // 1
Calendars.CALENDAR_DISPLAY_NAME, // 2
Calendars.OWNER_ACCOUNT // 3
};
// The indices for the projection array above.
final int PROJECTION_ID_INDEX = 0;
final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
final int PROJECTION_DISPLAY_NAME_INDEX = 2;
final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
// Run query
Cursor cur = null;
ContentResolver cr = app.getContentResolver();
Uri uri = Calendars.CONTENT_URI;
String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
+ Calendars.ACCOUNT_TYPE + " = ?) AND ("
+ Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[] { "sample#gmail.com",
"com.google", "sample#gmail.com" };
// Submit the query and get a Cursor object back.
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs,
null);
// Use the cursor to step through the returned records
while (cur.moveToNext()) {
// Get the field values
calID = cur.getLong(PROJECTION_ID_INDEX);
displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
}
Calendar beginTime = Calendar.getInstance();
Calendar ceaseTime = Calendar.getInstance();
ContentValues cv = new ContentValues();
HashMap<String, String> map = (HashMap<String, String>) params[0];
String startDate[] = map.get("startDate").toString().split("-");
String startTime[] = map.get("startTime").toString().split(":");
long beginMilis=0,ceaseMilis=0;
beginTime.set(Integer.parseInt(startDate[2]),
Integer.parseInt(startDate[1]),
Integer.parseInt(startDate[0]),
Integer.parseInt(startTime[0]),
Integer.parseInt(startTime[1]));
beginMilis = beginTime.getTimeInMillis();
String endDate[] = map.get("endDate").toString().split("-");
String endTime[] = map.get("endTime").toString().split(":");
TimeZone tz = TimeZone.getDefault();
ceaseTime.set(Integer.parseInt(endDate[2]),
Integer.parseInt(endDate[1]),
Integer.parseInt(endDate[0]),
Integer.parseInt(endTime[0]),
Integer.parseInt(endTime[1]));
ceaseMilis = ceaseTime.getTimeInMillis();
cv.put(Events.DTSTART, beginMilis);
cv.put(Events.DTEND, ceaseMilis);
cv.put(Events.TITLE, map.get("title").toString());
cv.put(Events.DESCRIPTION, map.get("description").toString());
cv.put(Events.CALENDAR_ID, String.valueOf(calID));
cv.put(Events.EVENT_TIMEZONE, tz.getDisplayName());
uri = cr.insert(Events.CONTENT_URI, cv);

Failing to query the max number in database

I am trying to find the max number in a column of one of the tables in my database.
I thought I had this one sorted (I posted similar question previously), however after some testing I have realised my code isn't working as I thought.
The database consists of a table with the following columns:
_id, inspection_link, area_number, area_reference
I have created the following code in my database helper class:
public static final String AREAS_TABLE = "areas";
public static final String AREA_ID = "_id";
public static final String AREA_NUMBER = "area_number";
public static final String AREA_REF = "area_reference";
public static final String AREA_LINK = "area_link";
public static final String INSPECTION_LINK = "inspection_link";
public Cursor selectMaxAreaNumber (long inspectionId) {
String inspectionIdString = String.valueOf(inspectionId);
String[] tableColumns = new String[] {
AREA_NUMBER,
"(SELECT max(" + AREA_NUMBER + ") FROM " + AREAS_TABLE + ") AS max"
};
String whereClause = INSPECTION_LINK + " = ?";
String[] whereArgs = new String[] {
inspectionIdString
};
Cursor c = rmDb.query(AREAS_TABLE, tableColumns, whereClause, whereArgs,
null, null, null);
if (c != null) {
c.moveToFirst();
}
c.close();
return c;
}
Then in the activity where I want to query the database I have written the following:
public class AreaEdit extends Activity {
private EditText AreaNumber;
private EditText AreaReference;
private Button saveButton;
private Button cancelButton;
protected boolean changesMade;
private AlertDialog unsavedChangesDialog;
private RMDbAdapter rmDbHelper;
private long inspectionId;
private long areaId;
private int nextAreaNumber = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rmDbHelper = new RMDbAdapter(this);
rmDbHelper.open();
Intent i = getIntent();
inspectionId = i.getLongExtra("Intent_InspectionID", -1);
areaId = i.getLongExtra("Intent_AreaID", -1);
if (areaId == -1) {
Cursor c = rmDbHelper.selectMaxAreaNumber(inspectionId);
startManagingCursor(c);
c.moveToFirst();
nextAreaNumber = c.getInt(c.getColumnIndex("max")) + 1;
}
setContentView(R.layout.edit_area);
setUpViews();
populateFields();
setTextChangedListeners();
}
private void setUpViews() {
AreaNumber =(EditText)findViewById(R.id.area_number);
AreaReference =(EditText)findViewById(R.id.area_reference);
saveButton = (Button)findViewById(R.id.area_save_button);
cancelButton = (Button)findViewById(R.id.area_cancel_button);
}
private void populateFields() {
if (areaId > 0) {
Cursor c = rmDbHelper.fetchArea(areaId);
startManagingCursor(c);
c.moveToFirst();
AreaNumber.setText(c.getString(
c.getColumnIndexOrThrow(RMDbAdapter.AREA_NUMBER)));
AreaReference.setText(c.getString(
c.getColumnIndexOrThrow(RMDbAdapter.AREA_REF)));
c.close();
}
else {
AreaNumber.setText(String.valueOf(nextAreaNumber));
}
}
However, when it returns the wrong number - it seems to pick up the maximum number from the whole table which includes data from other inspections.
I guess this may be down to the conversion between Strings and Longs etc maybe, but I have a brickwall with this?
Any help much appreciated.
You can simply try below:
String sql = "SELECT MAX(ColumnNameHere) AS MaxValue FROM myTable WHERE AnotherColumn = 'SomValue'";
Cursor c = db.rawQuery(sql, null);
c.moveToFirst();
c.getInt(c.getColumnIndex("MaxValue"));
Detailed solution to this question found here:
Solution to this detailed in the following post: SELECT statement not returning MAX number
Basically, it was an issue with the query as thought and how I used the cursor.

How can I read the favorites contacts inside service?

I am looking for a way to get the contacts in the favorites list inside service from phone number or from name it dose not matter. Can any one help me with this?
It's not important to use any code related to this code
I found in the developer.android.com something like this (IN_VISIBLE_GROUP).
How to use this variable in my case?
case (PICK_CONTACT):
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
Cursor c = managedQuery(contactData, null, null, null, null);
ContentResolver cr = getContentResolver();
if (c.moveToFirst()) {
String name = c.getString(c.getColumnIndexOrThrow(People.NAME));
String id =c.getString(c.getColumnIndexOrThrow(People._ID));
Cursor phones = cr.query(Phone.CONTENT_URI, null,
Phone.CONTACT_ID + " = " + id, null, null);
}
Lets assume that you are searching a contact by name..
If you want to get Favourite value of all the possible contacts , drop the selection parameter in the given code.
//First get the contact ID from a display name as:-
String displayName = "Albert Einstein";
Uri contacts = ContactsContract.Contacts.CONTENT_URI;
cur = cr.query(contacts, null, ContactsContract.Contacts.DISPLAY_NAME +"="+displayName,null, null);
int contactIdIndex = cur.getColumnIndex(ContactsContract.PhoneLookup._ID);
int contactId = cur.getInt(contactIdIndex);
//Make a query to get the Starred value:-
Cursor starred = cr.query(ContactsContract.Contacts.CONTENT_URI,
new String[] { ContactsContract.Contacts.STARRED },
ContactsContract.Contacts._ID + " = " + contactId,
null, null);
if (starred != null && starred.moveToFirst())
{
int fav = starred.getInt(0);
}
if (starred != null)
starred.close();
}
You can drop the step of getting Contact ID and then querying for Starred value and directly query based on Display name
Something like this?
final private static class DataQuery {
public static final int COLUMN_MIMETYPE = 1;
public static final int COLUMN_PHONE = 2;
public static final int COLUMN_RAWCONTACT_ID = 3;
public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1;
public static final String[] PROJECTION = new String[] { Data._ID, Data.MIMETYPE, Data.DATA1, Data.RAW_CONTACT_ID };
public static final String SELECTION_PHONE = Data.DATA1 + "=?";
}
long findContact(Context context, String number) {
long rawContactId = -1;
final Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION_PHONE, new String[] { number }, null);
try {
if (cursor.moveToFirst()) {
rawContactId = cursor.getLong(DataQuery.COLUMN_RAWCONTACT_ID);
}
} finally {
if (cursor != null)
cursor.close();
}
return rawContactId;
}
Ok let's try with this...
private static final Uri DATAGROUP_CONTENT_URI = ContactsContract.Data.CONTENT_URI.buildUpon().appendQueryParameter(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE).build();
public static void querytGroups(Context context) {
final ContentResolver resolver = context.getContentResolver();
long groupid=getGroupId(resolver, "Family");
final Cursor c = resolver.query(DATAGROUP_CONTENT_URI, DataQueryForContactsInGroup.PROJECTION, DataQueryForContactsInGroup.SELECTION, new String[] {ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupid)}, null);
try {
while (c.moveToNext()) {
final long rawContactId = c.getLong(DataQueryForContactsInGroup.RAW_CONTACT_ID);
//do something
}
}finally {
c.close();
}
}
private static long getGroupId(final ContentResolver resolver, String groupName) {
long groupid = -1;
Cursor cur = null;
try {
cur = resolver.query(Groups.CONTENT_URI, DataQueryForGroup.PROJECTION, DataQueryForGroup.SELECTION, new String[]{"%"+groupName+"%"}, null);
while (cur.moveToNext()) {
return groupid= cur.getLong(DataQueryForGroup.GROUP_ID);
}
}finally {
if (cur!=null) cur.close();
}
return groupid;
}
private interface DataQueryForGroup {
public final static String[] PROJECTION = new String[] {Groups._ID};
public static final String SELECTION = Groups.TITLE+" LIKE ?";
public final static int GROUP_ID = 0;
}
private interface DataQueryForContactsInGroup {
public final static String[] PROJECTION = new String[] { Data.RAW_CONTACT_ID };
public static final String SELECTION = "("+Data.MIMETYPE + "=?) and ("+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID+ "=?)";
public final static int RAW_CONTACT_ID = 0;
}
Please consider that if your google account is not English you need to look for the proper group's name

Categories

Resources