You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
etesync-android/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java

209 lines
7.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright © 2013 2015 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.resource;
import android.accounts.Account;
import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import java.security.acl.Group;
import java.util.LinkedList;
import java.util.List;
import at.bitfire.davdroid.Constants;
import at.bitfire.vcard4android.AndroidAddressBook;
import at.bitfire.vcard4android.AndroidContact;
import at.bitfire.vcard4android.AndroidGroupFactory;
import at.bitfire.vcard4android.ContactsStorageException;
import lombok.Cleanup;
public class LocalAddressBook extends AndroidAddressBook implements LocalCollection {
protected static final String
SYNC_STATE_CTAG = "ctag",
SYNC_STATE_URL = "url";
private Bundle syncState = new Bundle();
public LocalAddressBook(Account account, ContentProviderClient provider) {
super(account, provider, AndroidGroupFactory.INSTANCE, LocalContact.Factory.INSTANCE);
}
/**
* Returns an array of local contacts, excluding those which have been modified locally (and not uploaded yet).
*/
@Override
public LocalContact[] getAll() throws ContactsStorageException {
return (LocalContact[])queryContacts(null, null);
}
/**
* Returns an array of local contacts which have been deleted locally. (DELETED != 0).
*/
@Override
public LocalContact[] getDeleted() throws ContactsStorageException {
return (LocalContact[])queryContacts(RawContacts.DELETED + "!=0", null);
}
/**
* Returns an array of local contacts which have been changed locally (DIRTY != 0).
*/
@Override
public LocalContact[] getDirty() throws ContactsStorageException {
return (LocalContact[])queryContacts(RawContacts.DIRTY + "!=0", null);
}
/**
* Returns an array of local contacts which don't have a file name yet.
*/
@Override
public LocalContact[] getWithoutFileName() throws ContactsStorageException {
return (LocalContact[])queryContacts(AndroidContact.COLUMN_FILENAME + " IS NULL", null);
}
// GROUPS
/**
* Finds the first group with the given title.
* @param displayName title of the group to look for
* @return group with given title, or null if none
*/
@SuppressWarnings("Recycle")
public LocalGroup findGroupByTitle(String displayName) throws ContactsStorageException {
try {
@Cleanup Cursor cursor = provider.query(syncAdapterURI(Groups.CONTENT_URI),
new String[] { Groups._ID },
ContactsContract.Groups.TITLE + "=?", new String[] { displayName }, null);
if (cursor != null && cursor.moveToNext())
return new LocalGroup(this, cursor.getLong(0));
} catch (RemoteException e) {
throw new ContactsStorageException("Couldn't find local contact group", e);
}
return null;
}
@SuppressWarnings("Recycle")
public LocalGroup[] getDeletedGroups() throws ContactsStorageException {
List<LocalGroup> groups = new LinkedList<>();
try {
@Cleanup Cursor cursor = provider.query(syncAdapterURI(Groups.CONTENT_URI),
new String[] { Groups._ID },
Groups.DELETED + "!=0", null, null);
while (cursor != null && cursor.moveToNext())
groups.add(new LocalGroup(this, cursor.getLong(0)));
} catch (RemoteException e) {
throw new ContactsStorageException("Couldn't query deleted groups", e);
}
return groups.toArray(new LocalGroup[groups.size()]);
}
@SuppressWarnings("Recycle")
public LocalGroup[] getDirtyGroups() throws ContactsStorageException {
List<LocalGroup> groups = new LinkedList<>();
try {
@Cleanup Cursor cursor = provider.query(syncAdapterURI(Groups.CONTENT_URI),
new String[] { Groups._ID },
Groups.DIRTY + "!=0", null, null);
while (cursor != null && cursor.moveToNext())
groups.add(new LocalGroup(this, cursor.getLong(0)));
} catch (RemoteException e) {
throw new ContactsStorageException("Couldn't query dirty groups", e);
}
return groups.toArray(new LocalGroup[groups.size()]);
}
@SuppressWarnings("Recycle")
public void markMembersDirty(long groupId) throws ContactsStorageException {
ContentValues dirty = new ContentValues(1);
dirty.put(RawContacts.DIRTY, 1);
try {
// query all GroupMemberships of this groupId, mark every corresponding raw contact as DIRTY
@Cleanup Cursor cursor = provider.query(syncAdapterURI(Data.CONTENT_URI),
new String[] { GroupMembership.RAW_CONTACT_ID },
Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId) }, null);
while (cursor != null && cursor.moveToNext()) {
long id = cursor.getLong(0);
Constants.log.debug("Marking raw contact #" + id + " as dirty");
provider.update(syncAdapterURI(ContentUris.withAppendedId(RawContacts.CONTENT_URI, id)), dirty, null, null);
}
} catch (RemoteException e) {
throw new ContactsStorageException("Couldn't query dirty groups", e);
}
}
// SYNC STATE
@SuppressWarnings("Recycle")
protected void readSyncState() throws ContactsStorageException {
@Cleanup("recycle") Parcel parcel = Parcel.obtain();
byte[] raw = getSyncState();
if (raw != null) {
parcel.unmarshall(raw, 0, raw.length);
parcel.setDataPosition(0);
syncState = parcel.readBundle();
} else
syncState.clear();
}
@SuppressWarnings("Recycle")
protected void writeSyncState() throws ContactsStorageException {
@Cleanup("recycle") Parcel parcel = Parcel.obtain();
parcel.writeBundle(syncState);
setSyncState(parcel.marshall());
}
public String getURL() throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
return syncState.getString(SYNC_STATE_URL);
}
}
public void setURL(String url) throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
syncState.putString(SYNC_STATE_URL, url);
writeSyncState();
}
}
@Override
public String getCTag() throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
return syncState.getString(SYNC_STATE_CTAG);
}
}
@Override
public void setCTag(String cTag) throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
syncState.putString(SYNC_STATE_CTAG, cTag);
writeSyncState();
}
}
}