Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.

Commit

Permalink
resolves #35 where contacts not associated with an account (also know…
Browse files Browse the repository at this point in the history
…n as 'local contacts') were not possible to import from the 'Import contacts' fragment.
  • Loading branch information
rhodey committed Sep 17, 2014
1 parent e467dfe commit 0971870
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private void handleContactCopied(Account fromAccount) {

notificationBuilder
.setContentText(getString(R.string.notification_importing_contacts_from) +
" " + fromAccount.name)
" " + ((fromAccount != null) ? fromAccount.name : getString(R.string.local_storage)))
.setProgress(countContactsToCopy, countContactsCopied + countContactCopiesFailed, false);

notifyManager.notify(1023, notificationBuilder.build());
Expand Down Expand Up @@ -188,8 +188,12 @@ private void handleStartCopy() {
.acquireContentProviderClient(AddressbookSyncScheduler.CONTENT_AUTHORITY);

for (Pair<Account, Account> copyPair : accountsForCopy) {
LocalContactCollection fromCollection =
new LocalContactCollection(getBaseContext(), client, copyPair.first, "hack");
LocalContactCollection fromCollection = null;

if (!copyPair.first.type.equals(getString(R.string.local_storage)))
fromCollection = new LocalContactCollection(getBaseContext(), client, copyPair.first, "hack");
else
fromCollection = new LocalContactCollection(getBaseContext(), client, null, "hack");

try {

Expand All @@ -214,7 +218,10 @@ public void onContactCopied(Account fromAccount, Account toAccount) {

@Override
public void onContactCopyFailed(Exception e, Account fromAccount, Account toAccount) {
Log.e(TAG, "onContactCopyFailed() from " + fromAccount.name + " to " + toAccount.name, e);
Log.e(TAG, "onContactCopyFailed() from " +
((fromAccount != null) ? fromAccount.name : getString(R.string.local_storage)) +
" to " +
((toAccount != null) ? toAccount.name : getString(R.string.local_storage)), e);
handleContactCopyFailed(fromAccount);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private void initButtons() {

@Override
public void onClick(View view) {
Intent copyService = new Intent(getActivity(), ContactCopyService.class);
Intent copyService = new Intent(getActivity(), ContactCopyService.class);

if (selectedAccounts.size() == 0) {
handleBackgroundImportStarted();
Expand Down Expand Up @@ -217,15 +217,26 @@ protected void onPreExecute() {
protected void populateAccountContactCounts(List<AccountContactDetails> accounts)
throws RemoteException
{
ContentProviderClient client = getActivity().getContentResolver()
Uri rawContactsUri = null;
Cursor cursor = null;
ContentProviderClient client = getActivity().getContentResolver()
.acquireContentProviderClient(AddressbookSyncScheduler.CONTENT_AUTHORITY);

for (AccountContactDetails accountDetails : accounts) {
Uri rawContactsUri = LocalContactCollection
.getSyncAdapterUri(ContactsContract.RawContacts.CONTENT_URI, accountDetails.account);
if (!accountDetails.account.type.equals(getString(R.string.local_storage))) {
rawContactsUri = LocalContactCollection
.getSyncAdapterUri(ContactsContract.RawContacts.CONTENT_URI, accountDetails.account);
cursor = client.query(rawContactsUri, null, null, null, null);
accountDetails.contact_count = cursor.getCount();
Log.d(TAG, "account with type " + accountDetails.account.type + " has " + accountDetails.contact_count + " contacts");
}

Cursor cursor = client.query(rawContactsUri, null, null, null, null);
accountDetails.contact_count = cursor.getCount();
else {
rawContactsUri = ContactsContract.RawContacts.CONTENT_URI;
cursor = client.query(rawContactsUri, null, ContactsContract.RawContacts.ACCOUNT_TYPE + " IS NULL", null, null);
accountDetails.contact_count = cursor.getCount();
Log.d(TAG, "local storage has " + accountDetails.contact_count + " contacts");
}

cursor.close();
}
Expand All @@ -241,6 +252,11 @@ protected List<AccountContactDetails> getOtherAccounts() {
accounts.add(new AccountContactDetails(osAccount, 0));
}
}
accounts.add(
new AccountContactDetails(
new Account(getString(R.string.local_storage), getString(R.string.local_storage)),0
)
);

return accounts;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public Long getLocalId() {
protected abstract String getColumnNameDirty();
protected abstract String getColumnNameDeleted();
protected abstract String getColumnNameQueuedForMigration();
protected abstract String getColumnNameAccountType();

public List<Long> getNewComponentIds() throws RemoteException {
final String[] PROJECTION = new String[]{getColumnNameComponentLocalId(), getColumnNameComponentUid()};
Expand Down Expand Up @@ -152,10 +153,19 @@ public List<Pair<Long, String>> getDeletedComponentIds() throws RemoteException

public List<Long> getComponentIds() throws RemoteException {
final String[] PROJECTION = new String[]{getColumnNameComponentLocalId(), getColumnNameComponentUid()};
final String SELECTION = getColumnNameDeleted() + "=0 AND " +
getColumnNameCollectionLocalId() + "=" + localId;
String selection = null;

Cursor cursor = client.query(getUriForComponents(), PROJECTION, SELECTION, null, null);
if (account != null) {
selection = getColumnNameDeleted() + "=0 AND " +
getColumnNameCollectionLocalId() + "=" + localId;
}
else {
selection = getColumnNameDeleted() + "=0 AND " +
getColumnNameCollectionLocalId() + "=" + localId + " AND " +
getColumnNameAccountType() + " IS NULL";
}

Cursor cursor = client.query(getUriForComponents(), PROJECTION, selection, null, null);
List<Long> newIds = new LinkedList<Long>();

if (cursor == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,8 @@

package org.anhonesteffort.flock.sync.addressbook;

import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Log;

Expand All @@ -52,7 +47,6 @@
import ezvcard.property.Telephone;
import ezvcard.property.Uid;
import ezvcard.property.Url;
import ezvcard.util.IOUtils;

import org.anhonesteffort.flock.util.Base64;
import org.anhonesteffort.flock.webdav.carddav.CardDavConstants;
Expand All @@ -61,9 +55,7 @@
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
Expand Down Expand Up @@ -542,37 +534,6 @@ else if (isSuperPrimary != null && isSuperPrimary)
}
}

private static Uri getUriForDisplayPhoto(Long rawContactId) {
Uri rawContactUri = ContentUris.withAppendedId(
ContactsContract.RawContacts.CONTENT_URI,
rawContactId
);

return Uri.withAppendedPath(rawContactUri, ContactsContract.RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
}

protected static Optional<Photo> getDisplayPhoto(String path,
ContentProviderClient client,
Long rawContactId)
throws InvalidComponentException, RemoteException
{
try {

AssetFileDescriptor fileDescriptor = client.openAssetFile(getUriForDisplayPhoto(rawContactId), "r");
InputStream inputStream = fileDescriptor.createInputStream();

return Optional.of(
new Photo(IOUtils.toByteArray(inputStream), ImageType.JPEG)
);

} catch (FileNotFoundException e) {
return Optional.absent();
} catch (IOException e) {
throw new InvalidComponentException("caught exception while adding picture", false,
CardDavConstants.CARDDAV_NAMESPACE, path);
}
}

protected static String[] getProjectionForThumbnailPhoto() {
return new String[] {
ContactsContract.CommonDataKinds.Photo.PHOTO // 00 raw bytes of image
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.content.Context;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
Expand All @@ -35,13 +36,18 @@

import com.google.common.base.Optional;
import ezvcard.VCard;
import ezvcard.parameter.ImageType;
import ezvcard.property.Photo;
import ezvcard.util.IOUtils;

import org.anhonesteffort.flock.webdav.carddav.CardDavConstants;
import org.anhonesteffort.flock.sync.AbstractLocalComponentCollection;
import org.anhonesteffort.flock.webdav.ComponentETagPair;
import org.anhonesteffort.flock.webdav.InvalidComponentException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

Expand Down Expand Up @@ -72,10 +78,15 @@ private String getKeyForCTag() {
}

public static Uri getSyncAdapterUri(Uri base, Account account) {
if (account != null)
return base.buildUpon()
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();

return base.buildUpon()
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
}

Expand All @@ -101,6 +112,15 @@ private Uri getUriForData() {
return getSyncAdapterUri(ContactsContract.Data.CONTENT_URI);
}

private static Uri getUriForDisplayPhoto(Long rawContactId) {
Uri rawContactUri = ContentUris.withAppendedId(
ContactsContract.RawContacts.CONTENT_URI,
rawContactId
);

return Uri.withAppendedPath(rawContactUri, ContactsContract.RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
}

@Override
protected String getColumnNameCollectionLocalId() {
return "1"; // hack :D
Expand Down Expand Up @@ -140,6 +160,11 @@ protected String getColumnNameQueuedForMigration() {
return ContactsContract.RawContacts.SYNC2;
}

@Override
protected String getColumnNameAccountType() {
return ContactsContract.RawContacts.ACCOUNT_TYPE;
}

@Override
public Optional<String> getDisplayName() {
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_NAME,
Expand Down Expand Up @@ -237,6 +262,26 @@ private void addEmailAddresses(Long rawContactId, VCard vCard)
cursor.close();
}

private Optional<Photo> getDisplayPhoto(Long rawContactId)
throws InvalidComponentException, RemoteException
{
try {

AssetFileDescriptor fileDescriptor = client.openAssetFile(getUriForDisplayPhoto(rawContactId), "r");
InputStream inputStream = fileDescriptor.createInputStream();

return Optional.of(
new Photo(IOUtils.toByteArray(inputStream), ImageType.JPEG)
);

} catch (FileNotFoundException e) {
return Optional.absent();
} catch (IOException e) {
throw new InvalidComponentException("caught exception while adding picture", false,
CardDavConstants.CARDDAV_NAMESPACE, getPath());
}
}

private Optional<Photo> getThumbnailPhoto(Long rawContactId)
throws InvalidComponentException, RemoteException
{
Expand Down Expand Up @@ -266,7 +311,7 @@ private Optional<Photo> getThumbnailPhoto(Long rawContactId)
private void addPhotos(Long rawContactId, VCard vCard)
throws InvalidComponentException, RemoteException
{
Optional<Photo> photo = ContactFactory.getDisplayPhoto(getPath(), client, rawContactId);
Optional<Photo> photo = getDisplayPhoto(rawContactId);
if (!photo.isPresent())
photo = getThumbnailPhoto(rawContactId);

Expand Down Expand Up @@ -740,11 +785,12 @@ public void updateComponent(ComponentETagPair<VCard> vCard)
public void copyToAccount(Account toAccount, ContactCopiedListener listener)
throws InvalidComponentException, RemoteException
{
Log.d(TAG, "copy my " + getComponentIds().size() + " contacts to " + toAccount.name);
LocalContactCollection toCollection = new LocalContactCollection(context, client, toAccount, getPath());
List<Long> componentIds = getComponentIds();

LocalContactCollection toCollection = new LocalContactCollection(context, client, toAccount, getPath());
Log.d(TAG, "copy my " + componentIds.size() + " contacts to " + toAccount.name);

for (Long contactId : getComponentIds()) {
for (Long contactId : componentIds) {
try {

Optional<VCard> copyContact = getComponent(contactId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,12 @@ private Uri getCollectionUri() {

@Override
protected Uri getUriForComponents() {
return getSyncAdapterUri(CalendarContract.Events.CONTENT_URI);
if (account != null)
return getSyncAdapterUri(CalendarContract.Events.CONTENT_URI);

return CalendarContract.Events.CONTENT_URI.buildUpon()
.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
.build();
}

private Uri getUriForAttendees() {
Expand Down Expand Up @@ -154,6 +159,11 @@ protected String getColumnNameQueuedForMigration() {
return CalendarContract.Events.SYNC_DATA3;
}

@Override
protected String getColumnNameAccountType() {
return CalendarContract.Events.ACCOUNT_TYPE;
}

@Override
public List<Long> getNewComponentIds() throws RemoteException {
final String[] PROJECTION = new String[]{getColumnNameComponentLocalId()};
Expand Down
1 change: 1 addition & 0 deletions flock/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
<!-- SetupActivity, import -->
<string name="button_import">Import</string>
<string name="import_complete">Import complete!</string>
<string name="local_storage">Local storage</string>


<!-- SetupActivity, import contacts -->
Expand Down

1 comment on commit 0971870

@WhisperBTC
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! BitHub has sent payment of $17.22USD for this commit.

Please sign in to comment.