| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.loaderapp.model; |
| |
| import com.android.loaderapp.R; |
| import com.android.loaderapp.model.EntityDelta.ValuesDelta; |
| import com.google.android.collect.Lists; |
| |
| import android.accounts.Account; |
| import android.content.ContentProviderOperation; |
| import android.content.ContentProviderResult; |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.OperationApplicationException; |
| import android.database.Cursor; |
| import android.os.RemoteException; |
| import android.provider.ContactsContract; |
| import android.provider.ContactsContract.Groups; |
| import android.provider.ContactsContract.RawContacts; |
| import android.provider.ContactsContract.CommonDataKinds.Email; |
| import android.provider.ContactsContract.CommonDataKinds.GroupMembership; |
| import android.provider.ContactsContract.CommonDataKinds.Phone; |
| import android.provider.ContactsContract.Contacts.Data; |
| |
| import java.util.ArrayList; |
| |
| public class GoogleSource extends FallbackSource { |
| public static final String ACCOUNT_TYPE = "com.google"; |
| public GoogleSource(String resPackageName) { |
| this.accountType = ACCOUNT_TYPE; |
| this.resPackageName = null; |
| this.summaryResPackageName = resPackageName; |
| } |
| |
| @Override |
| protected void inflate(Context context, int inflateLevel) { |
| |
| inflateStructuredName(context, inflateLevel); |
| inflateNickname(context, inflateLevel); |
| inflatePhone(context, inflateLevel); |
| inflateEmail(context, inflateLevel); |
| inflateStructuredPostal(context, inflateLevel); |
| inflateIm(context, inflateLevel); |
| inflateOrganization(context, inflateLevel); |
| inflatePhoto(context, inflateLevel); |
| inflateNote(context, inflateLevel); |
| inflateWebsite(context, inflateLevel); |
| inflateEvent(context, inflateLevel); |
| |
| // TODO: GOOGLE: GROUPMEMBERSHIP |
| |
| setInflatedLevel(inflateLevel); |
| |
| } |
| |
| @Override |
| protected DataKind inflateStructuredName(Context context, int inflateLevel) { |
| return super.inflateStructuredName(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflateNickname(Context context, int inflateLevel) { |
| return super.inflateNickname(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflatePhone(Context context, int inflateLevel) { |
| final DataKind kind = super.inflatePhone(context, ContactsSource.LEVEL_MIMETYPES); |
| |
| if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) { |
| kind.typeColumn = Phone.TYPE; |
| kind.typeList = Lists.newArrayList(); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_HOME)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_WORK)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER)); |
| kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn( |
| Phone.LABEL)); |
| |
| kind.fieldList = Lists.newArrayList(); |
| kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE)); |
| } |
| |
| return kind; |
| } |
| |
| @Override |
| protected DataKind inflateEmail(Context context, int inflateLevel) { |
| final DataKind kind = super.inflateEmail(context, ContactsSource.LEVEL_MIMETYPES); |
| |
| if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) { |
| kind.typeColumn = Email.TYPE; |
| kind.typeList = Lists.newArrayList(); |
| kind.typeList.add(buildEmailType(Email.TYPE_HOME)); |
| kind.typeList.add(buildEmailType(Email.TYPE_WORK)); |
| kind.typeList.add(buildEmailType(Email.TYPE_OTHER)); |
| kind.typeList.add(buildEmailType(Email.TYPE_CUSTOM).setSecondary(true).setCustomColumn( |
| Email.LABEL)); |
| |
| kind.fieldList = Lists.newArrayList(); |
| kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL)); |
| } |
| |
| return kind; |
| } |
| |
| @Override |
| protected DataKind inflateStructuredPostal(Context context, int inflateLevel) { |
| return super.inflateStructuredPostal(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflateIm(Context context, int inflateLevel) { |
| return super.inflateIm(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflateOrganization(Context context, int inflateLevel) { |
| return super.inflateOrganization(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflatePhoto(Context context, int inflateLevel) { |
| return super.inflatePhoto(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflateNote(Context context, int inflateLevel) { |
| return super.inflateNote(context, inflateLevel); |
| } |
| |
| @Override |
| protected DataKind inflateWebsite(Context context, int inflateLevel) { |
| return super.inflateWebsite(context, inflateLevel); |
| } |
| |
| // TODO: this should come from resource in the future |
| // Note that frameworks/base/core/java/android/pim/vcard/ContactStruct.java also wants |
| // this String. |
| private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts"; |
| |
| public static final void attemptMyContactsMembership(EntityDelta state, Context context) { |
| final ValuesDelta stateValues = state.getValues(); |
| stateValues.setFromTemplate(true); |
| final String accountName = stateValues.getAsString(RawContacts.ACCOUNT_NAME); |
| final String accountType = stateValues.getAsString(RawContacts.ACCOUNT_TYPE); |
| attemptMyContactsMembership(state, accountName, accountType, context, true); |
| } |
| |
| public static final void createMyContactsIfNotExist(Account account, Context context) { |
| attemptMyContactsMembership(null, account.name, account.type, context, true); |
| } |
| |
| /** |
| * |
| * @param allowRecur If the group is created between querying/about to create, we recur. But |
| * to prevent excess recursion, we provide a flag to make sure we only do the recursion loop |
| * once |
| */ |
| private static final void attemptMyContactsMembership(EntityDelta state, |
| final String accountName, final String accountType, Context context, |
| boolean allowRecur) { |
| final ContentResolver resolver = context.getContentResolver(); |
| |
| Cursor cursor = resolver.query(Groups.CONTENT_URI, |
| new String[] {Groups.TITLE, Groups.SOURCE_ID, Groups.SHOULD_SYNC}, |
| Groups.ACCOUNT_NAME + " =? AND " + Groups.ACCOUNT_TYPE + " =?", |
| new String[] {accountName, accountType}, null); |
| |
| boolean myContactsExists = false; |
| long assignToGroupSourceId = -1; |
| while (cursor.moveToNext()) { |
| if (GOOGLE_MY_CONTACTS_GROUP.equals(cursor.getString(0))) { |
| myContactsExists = true; |
| } |
| if (assignToGroupSourceId == -1 && cursor.getInt(2) != 0) { |
| assignToGroupSourceId = cursor.getInt(1); |
| } |
| |
| if (myContactsExists && assignToGroupSourceId != -1) { |
| break; |
| } |
| } |
| |
| if (myContactsExists && state == null) { |
| return; |
| } |
| |
| try { |
| final ContentValues values = new ContentValues(); |
| values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); |
| |
| if (!myContactsExists) { |
| // create the group if it doesn't exist |
| final ContentValues newGroup = new ContentValues(); |
| newGroup.put(Groups.TITLE, GOOGLE_MY_CONTACTS_GROUP); |
| |
| newGroup.put(Groups.ACCOUNT_NAME, accountName); |
| newGroup.put(Groups.ACCOUNT_TYPE, accountType); |
| newGroup.put(Groups.GROUP_VISIBLE, "1"); |
| |
| ArrayList<ContentProviderOperation> operations = |
| new ArrayList<ContentProviderOperation>(); |
| |
| operations.add(ContentProviderOperation |
| .newAssertQuery(Groups.CONTENT_URI) |
| .withSelection(Groups.TITLE + "=?", |
| new String[] { GOOGLE_MY_CONTACTS_GROUP }) |
| .withExpectedCount(0).build()); |
| operations.add(ContentProviderOperation |
| |
| .newInsert(Groups.CONTENT_URI) |
| .withValues(newGroup) |
| .build()); |
| try { |
| ContentProviderResult[] results = resolver.applyBatch( |
| ContactsContract.AUTHORITY, operations); |
| values.put(GroupMembership.GROUP_ROW_ID, ContentUris.parseId(results[1].uri)); |
| } catch (RemoteException e) { |
| throw new IllegalStateException("Problem querying for groups", e); |
| } catch (OperationApplicationException e) { |
| // the group was created after the query but before we tried to create it |
| if (allowRecur) { |
| attemptMyContactsMembership( |
| state, accountName, accountType, context, false); |
| } |
| return; |
| } |
| } else { |
| if (assignToGroupSourceId != -1) { |
| values.put(GroupMembership.GROUP_SOURCE_ID, assignToGroupSourceId); |
| } else { |
| // there are no Groups to add this contact to, so don't apply any membership |
| // TODO: alert user that their contact will be dropped? |
| } |
| } |
| if (state != null) { |
| state.addEntry(ValuesDelta.fromAfter(values)); |
| } |
| } finally { |
| cursor.close(); |
| } |
| } |
| |
| @Override |
| public int getHeaderColor(Context context) { |
| return 0xff89c2c2; |
| } |
| |
| @Override |
| public int getSideBarColor(Context context) { |
| return 0xff5bb4b4; |
| } |
| } |