1273399bf829133a8385332ad43add3c34c889102Chiao Cheng/* 2273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Copyright (C) 2009 The Android Open Source Project 3273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 4273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 5273399bf829133a8385332ad43add3c34c889102Chiao Cheng * you may not use this file except in compliance with the License. 6273399bf829133a8385332ad43add3c34c889102Chiao Cheng * You may obtain a copy of the License at 7273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 8273399bf829133a8385332ad43add3c34c889102Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 9273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 10273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Unless required by applicable law or agreed to in writing, software 11273399bf829133a8385332ad43add3c34c889102Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 12273399bf829133a8385332ad43add3c34c889102Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13273399bf829133a8385332ad43add3c34c889102Chiao Cheng * See the License for the specific language governing permissions and 14273399bf829133a8385332ad43add3c34c889102Chiao Cheng * limitations under the License. 15273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 16273399bf829133a8385332ad43add3c34c889102Chiao Cheng 17273399bf829133a8385332ad43add3c34c889102Chiao Chengpackage com.android.contacts.common.model.account; 18273399bf829133a8385332ad43add3c34c889102Chiao Cheng 19273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.Context; 20273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.pm.PackageInfo; 21273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.pm.PackageManager; 22273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.pm.PackageManager.NameNotFoundException; 23273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.pm.ServiceInfo; 24273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.res.Resources; 25273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.res.TypedArray; 26273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.content.res.XmlResourceParser; 27273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.provider.ContactsContract.CommonDataKinds.Photo; 28273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 29273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.text.TextUtils; 30273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.util.AttributeSet; 31273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.util.Log; 32273399bf829133a8385332ad43add3c34c889102Chiao Chengimport android.util.Xml; 33273399bf829133a8385332ad43add3c34c889102Chiao Cheng 343aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Leeimport com.android.contacts.common.R; 35273399bf829133a8385332ad43add3c34c889102Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind; 36273399bf829133a8385332ad43add3c34c889102Chiao Chengimport com.google.common.annotations.VisibleForTesting; 37273399bf829133a8385332ad43add3c34c889102Chiao Cheng 38273399bf829133a8385332ad43add3c34c889102Chiao Chengimport org.xmlpull.v1.XmlPullParser; 39273399bf829133a8385332ad43add3c34c889102Chiao Chengimport org.xmlpull.v1.XmlPullParserException; 40273399bf829133a8385332ad43add3c34c889102Chiao Cheng 41273399bf829133a8385332ad43add3c34c889102Chiao Chengimport java.io.IOException; 42273399bf829133a8385332ad43add3c34c889102Chiao Chengimport java.util.ArrayList; 43273399bf829133a8385332ad43add3c34c889102Chiao Chengimport java.util.List; 44273399bf829133a8385332ad43add3c34c889102Chiao Cheng 45273399bf829133a8385332ad43add3c34c889102Chiao Cheng/** 46273399bf829133a8385332ad43add3c34c889102Chiao Cheng * A general contacts account type descriptor. 47273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 48273399bf829133a8385332ad43add3c34c889102Chiao Chengpublic class ExternalAccountType extends BaseAccountType { 49273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String TAG = "ExternalAccountType"; 50273399bf829133a8385332ad43add3c34c889102Chiao Cheng 514e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki /** 524e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki * The metadata name for so-called "contacts.xml". 534e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki * 544e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki * On LMP and later, we also accept the "alternate" name. 554e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki * This is to allow sync adapters to have a contacts.xml without making it visible on older 564e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki * platforms. 574e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki */ 584e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki private static final String[] METADATA_CONTACTS_NAMES = new String[] { 594e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki "android.provider.ALTERNATE_CONTACTS_STRUCTURE", 604e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki "android.provider.CONTACTS_STRUCTURE" 614e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki }; 62273399bf829133a8385332ad43add3c34c889102Chiao Cheng 63273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String TAG_CONTACTS_SOURCE_LEGACY = "ContactsSource"; 64273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String TAG_CONTACTS_ACCOUNT_TYPE = "ContactsAccountType"; 65273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String TAG_CONTACTS_DATA_KIND = "ContactsDataKind"; 66273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String TAG_EDIT_SCHEMA = "EditSchema"; 67273399bf829133a8385332ad43add3c34c889102Chiao Cheng 68273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_EDIT_CONTACT_ACTIVITY = "editContactActivity"; 69273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_CREATE_CONTACT_ACTIVITY = "createContactActivity"; 70273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_INVITE_CONTACT_ACTIVITY = "inviteContactActivity"; 71273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_INVITE_CONTACT_ACTION_LABEL = "inviteContactActionLabel"; 72273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_VIEW_CONTACT_NOTIFY_SERVICE = "viewContactNotifyService"; 73273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_VIEW_GROUP_ACTIVITY = "viewGroupActivity"; 74273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_VIEW_GROUP_ACTION_LABEL = "viewGroupActionLabel"; 75273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_DATA_SET = "dataSet"; 76273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_EXTENSION_PACKAGE_NAMES = "extensionPackageNames"; 77273399bf829133a8385332ad43add3c34c889102Chiao Cheng 78273399bf829133a8385332ad43add3c34c889102Chiao Cheng // The following attributes should only be set in non-sync-adapter account types. They allow 79273399bf829133a8385332ad43add3c34c889102Chiao Cheng // for the account type and resource IDs to be specified without an associated authenticator. 80273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_ACCOUNT_TYPE = "accountType"; 81273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_ACCOUNT_LABEL = "accountTypeLabel"; 82273399bf829133a8385332ad43add3c34c889102Chiao Cheng private static final String ATTR_ACCOUNT_ICON = "accountTypeIcon"; 83273399bf829133a8385332ad43add3c34c889102Chiao Cheng 84273399bf829133a8385332ad43add3c34c889102Chiao Cheng private final boolean mIsExtension; 85273399bf829133a8385332ad43add3c34c889102Chiao Cheng 86273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mEditContactActivityClassName; 87273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mCreateContactActivityClassName; 88273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mInviteContactActivity; 89273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mInviteActionLabelAttribute; 90273399bf829133a8385332ad43add3c34c889102Chiao Cheng private int mInviteActionLabelResId; 91273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mViewContactNotifyService; 92273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mViewGroupActivity; 93273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mViewGroupLabelAttribute; 94273399bf829133a8385332ad43add3c34c889102Chiao Cheng private int mViewGroupLabelResId; 95273399bf829133a8385332ad43add3c34c889102Chiao Cheng private List<String> mExtensionPackageNames; 96273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mAccountTypeLabelAttribute; 97273399bf829133a8385332ad43add3c34c889102Chiao Cheng private String mAccountTypeIconAttribute; 98273399bf829133a8385332ad43add3c34c889102Chiao Cheng private boolean mHasContactsMetadata; 99273399bf829133a8385332ad43add3c34c889102Chiao Cheng private boolean mHasEditSchema; 100273399bf829133a8385332ad43add3c34c889102Chiao Cheng 101273399bf829133a8385332ad43add3c34c889102Chiao Cheng public ExternalAccountType(Context context, String resPackageName, boolean isExtension) { 102273399bf829133a8385332ad43add3c34c889102Chiao Cheng this(context, resPackageName, isExtension, null); 103273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 104273399bf829133a8385332ad43add3c34c889102Chiao Cheng 105273399bf829133a8385332ad43add3c34c889102Chiao Cheng /** 106273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Constructor used for testing to initialize with any arbitrary XML. 107273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 108273399bf829133a8385332ad43add3c34c889102Chiao Cheng * @param injectedMetadata If non-null, it'll be used to initialize the type. Only set by 109273399bf829133a8385332ad43add3c34c889102Chiao Cheng * tests. If null, the metadata is loaded from the specified package. 110273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 111273399bf829133a8385332ad43add3c34c889102Chiao Cheng ExternalAccountType(Context context, String packageName, boolean isExtension, 112273399bf829133a8385332ad43add3c34c889102Chiao Cheng XmlResourceParser injectedMetadata) { 113273399bf829133a8385332ad43add3c34c889102Chiao Cheng this.mIsExtension = isExtension; 114273399bf829133a8385332ad43add3c34c889102Chiao Cheng this.resourcePackageName = packageName; 115273399bf829133a8385332ad43add3c34c889102Chiao Cheng this.syncAdapterPackageName = packageName; 116273399bf829133a8385332ad43add3c34c889102Chiao Cheng 117273399bf829133a8385332ad43add3c34c889102Chiao Cheng final PackageManager pm = context.getPackageManager(); 118273399bf829133a8385332ad43add3c34c889102Chiao Cheng final XmlResourceParser parser; 119273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (injectedMetadata == null) { 120273399bf829133a8385332ad43add3c34c889102Chiao Cheng try { 121273399bf829133a8385332ad43add3c34c889102Chiao Cheng parser = loadContactsXml(context, packageName); 122273399bf829133a8385332ad43add3c34c889102Chiao Cheng } catch (NameNotFoundException e1) { 123273399bf829133a8385332ad43add3c34c889102Chiao Cheng // If the package name is not found, we can't initialize this account type. 124273399bf829133a8385332ad43add3c34c889102Chiao Cheng return; 125273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 126273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else { 127273399bf829133a8385332ad43add3c34c889102Chiao Cheng parser = injectedMetadata; 128273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 129273399bf829133a8385332ad43add3c34c889102Chiao Cheng boolean needLineNumberInErrorLog = true; 130273399bf829133a8385332ad43add3c34c889102Chiao Cheng try { 131273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (parser != null) { 132273399bf829133a8385332ad43add3c34c889102Chiao Cheng inflate(context, parser); 133273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 134273399bf829133a8385332ad43add3c34c889102Chiao Cheng 135273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Done parsing; line number no longer needed in error log. 136273399bf829133a8385332ad43add3c34c889102Chiao Cheng needLineNumberInErrorLog = false; 137273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (mHasEditSchema) { 138273399bf829133a8385332ad43add3c34c889102Chiao Cheng checkKindExists(StructuredName.CONTENT_ITEM_TYPE); 139273399bf829133a8385332ad43add3c34c889102Chiao Cheng checkKindExists(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME); 140273399bf829133a8385332ad43add3c34c889102Chiao Cheng checkKindExists(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME); 141273399bf829133a8385332ad43add3c34c889102Chiao Cheng checkKindExists(Photo.CONTENT_ITEM_TYPE); 142273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else { 143273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Bring in name and photo from fallback source, which are non-optional 144273399bf829133a8385332ad43add3c34c889102Chiao Cheng addDataKindStructuredName(context); 145273399bf829133a8385332ad43add3c34c889102Chiao Cheng addDataKindDisplayName(context); 146273399bf829133a8385332ad43add3c34c889102Chiao Cheng addDataKindPhoneticName(context); 147273399bf829133a8385332ad43add3c34c889102Chiao Cheng addDataKindPhoto(context); 148273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 149273399bf829133a8385332ad43add3c34c889102Chiao Cheng } catch (DefinitionException e) { 150273399bf829133a8385332ad43add3c34c889102Chiao Cheng final StringBuilder error = new StringBuilder(); 151273399bf829133a8385332ad43add3c34c889102Chiao Cheng error.append("Problem reading XML"); 152273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (needLineNumberInErrorLog && (parser != null)) { 153273399bf829133a8385332ad43add3c34c889102Chiao Cheng error.append(" in line "); 154273399bf829133a8385332ad43add3c34c889102Chiao Cheng error.append(parser.getLineNumber()); 155273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 156273399bf829133a8385332ad43add3c34c889102Chiao Cheng error.append(" for external package "); 157273399bf829133a8385332ad43add3c34c889102Chiao Cheng error.append(packageName); 158273399bf829133a8385332ad43add3c34c889102Chiao Cheng 159273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.e(TAG, error.toString(), e); 160273399bf829133a8385332ad43add3c34c889102Chiao Cheng return; 161273399bf829133a8385332ad43add3c34c889102Chiao Cheng } finally { 162273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (parser != null) { 163273399bf829133a8385332ad43add3c34c889102Chiao Cheng parser.close(); 164273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 165273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 166273399bf829133a8385332ad43add3c34c889102Chiao Cheng 167273399bf829133a8385332ad43add3c34c889102Chiao Cheng mExtensionPackageNames = new ArrayList<String>(); 168273399bf829133a8385332ad43add3c34c889102Chiao Cheng mInviteActionLabelResId = resolveExternalResId(context, mInviteActionLabelAttribute, 169273399bf829133a8385332ad43add3c34c889102Chiao Cheng syncAdapterPackageName, ATTR_INVITE_CONTACT_ACTION_LABEL); 170273399bf829133a8385332ad43add3c34c889102Chiao Cheng mViewGroupLabelResId = resolveExternalResId(context, mViewGroupLabelAttribute, 171273399bf829133a8385332ad43add3c34c889102Chiao Cheng syncAdapterPackageName, ATTR_VIEW_GROUP_ACTION_LABEL); 172273399bf829133a8385332ad43add3c34c889102Chiao Cheng titleRes = resolveExternalResId(context, mAccountTypeLabelAttribute, 173273399bf829133a8385332ad43add3c34c889102Chiao Cheng syncAdapterPackageName, ATTR_ACCOUNT_LABEL); 174273399bf829133a8385332ad43add3c34c889102Chiao Cheng iconRes = resolveExternalResId(context, mAccountTypeIconAttribute, 175273399bf829133a8385332ad43add3c34c889102Chiao Cheng syncAdapterPackageName, ATTR_ACCOUNT_ICON); 176273399bf829133a8385332ad43add3c34c889102Chiao Cheng 177273399bf829133a8385332ad43add3c34c889102Chiao Cheng // If we reach this point, the account type has been successfully initialized. 178273399bf829133a8385332ad43add3c34c889102Chiao Cheng mIsInitialized = true; 179273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 180273399bf829133a8385332ad43add3c34c889102Chiao Cheng 181273399bf829133a8385332ad43add3c34c889102Chiao Cheng /** 182273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Returns the CONTACTS_STRUCTURE metadata (aka "contacts.xml") in the given apk package. 183273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 184273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Unfortunately, there's no public way to determine which service defines a sync service for 185273399bf829133a8385332ad43add3c34c889102Chiao Cheng * which account type, so this method looks through all services in the package, and just 186273399bf829133a8385332ad43add3c34c889102Chiao Cheng * returns the first CONTACTS_STRUCTURE metadata defined in any of them. 187273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 188273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Returns {@code null} if the package has no CONTACTS_STRUCTURE metadata. In this case 189273399bf829133a8385332ad43add3c34c889102Chiao Cheng * the account type *will* be initialized with minimal configuration. 190273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 191273399bf829133a8385332ad43add3c34c889102Chiao Cheng * On the other hand, if the package is not found, it throws a {@link NameNotFoundException}, 192273399bf829133a8385332ad43add3c34c889102Chiao Cheng * in which case the account type will *not* be initialized. 193273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 194273399bf829133a8385332ad43add3c34c889102Chiao Cheng private XmlResourceParser loadContactsXml(Context context, String resPackageName) 195273399bf829133a8385332ad43add3c34c889102Chiao Cheng throws NameNotFoundException { 196273399bf829133a8385332ad43add3c34c889102Chiao Cheng final PackageManager pm = context.getPackageManager(); 197273399bf829133a8385332ad43add3c34c889102Chiao Cheng PackageInfo packageInfo = pm.getPackageInfo(resPackageName, 198273399bf829133a8385332ad43add3c34c889102Chiao Cheng PackageManager.GET_SERVICES|PackageManager.GET_META_DATA); 199273399bf829133a8385332ad43add3c34c889102Chiao Cheng for (ServiceInfo serviceInfo : packageInfo.services) { 2004e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki for (String metadataName : METADATA_CONTACTS_NAMES) { 2014e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki final XmlResourceParser parser = serviceInfo.loadXmlMetaData(pm, 2024e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki metadataName); 2034e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki if (parser != null) { 2044e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki if (Log.isLoggable(TAG, Log.DEBUG)) { 2054e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki Log.d(TAG, String.format("Metadata loaded from: %s, %s, %s", 2064e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki serviceInfo.packageName, serviceInfo.name, 2074e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki metadataName)); 2084e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki } 2094e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki return parser; 2104e5fe7c5aeaa8b5ed39cb958ab2e73d254cc3dadMakoto Onuki } 211273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 212273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 213273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Package was found, but that doesn't contain the CONTACTS_STRUCTURE metadata. 214273399bf829133a8385332ad43add3c34c889102Chiao Cheng return null; 215273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 216273399bf829133a8385332ad43add3c34c889102Chiao Cheng 217273399bf829133a8385332ad43add3c34c889102Chiao Cheng private void checkKindExists(String mimeType) throws DefinitionException { 218273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (getKindForMimetype(mimeType) == null) { 219273399bf829133a8385332ad43add3c34c889102Chiao Cheng throw new DefinitionException(mimeType + " must be supported"); 220273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 221273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 222273399bf829133a8385332ad43add3c34c889102Chiao Cheng 223273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 224273399bf829133a8385332ad43add3c34c889102Chiao Cheng public boolean isEmbedded() { 225273399bf829133a8385332ad43add3c34c889102Chiao Cheng return false; 226273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 227273399bf829133a8385332ad43add3c34c889102Chiao Cheng 228273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 229273399bf829133a8385332ad43add3c34c889102Chiao Cheng public boolean isExtension() { 230273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mIsExtension; 231273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 232273399bf829133a8385332ad43add3c34c889102Chiao Cheng 233273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 234273399bf829133a8385332ad43add3c34c889102Chiao Cheng public boolean areContactsWritable() { 235273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mHasEditSchema; 236273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 237273399bf829133a8385332ad43add3c34c889102Chiao Cheng 238273399bf829133a8385332ad43add3c34c889102Chiao Cheng /** 239273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Whether this account type has the android.provider.CONTACTS_STRUCTURE metadata xml. 240273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 241273399bf829133a8385332ad43add3c34c889102Chiao Cheng public boolean hasContactsMetadata() { 242273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mHasContactsMetadata; 243273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 244273399bf829133a8385332ad43add3c34c889102Chiao Cheng 245273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 246273399bf829133a8385332ad43add3c34c889102Chiao Cheng public String getEditContactActivityClassName() { 247273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mEditContactActivityClassName; 248273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 249273399bf829133a8385332ad43add3c34c889102Chiao Cheng 250273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 251273399bf829133a8385332ad43add3c34c889102Chiao Cheng public String getCreateContactActivityClassName() { 252273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mCreateContactActivityClassName; 253273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 254273399bf829133a8385332ad43add3c34c889102Chiao Cheng 255273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 256273399bf829133a8385332ad43add3c34c889102Chiao Cheng public String getInviteContactActivityClassName() { 257273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mInviteContactActivity; 258273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 259273399bf829133a8385332ad43add3c34c889102Chiao Cheng 260273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 261273399bf829133a8385332ad43add3c34c889102Chiao Cheng protected int getInviteContactActionResId() { 262273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mInviteActionLabelResId; 263273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 264273399bf829133a8385332ad43add3c34c889102Chiao Cheng 265273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 266273399bf829133a8385332ad43add3c34c889102Chiao Cheng public String getViewContactNotifyServiceClassName() { 267273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mViewContactNotifyService; 268273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 269273399bf829133a8385332ad43add3c34c889102Chiao Cheng 270273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 271273399bf829133a8385332ad43add3c34c889102Chiao Cheng public String getViewGroupActivity() { 272273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mViewGroupActivity; 273273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 274273399bf829133a8385332ad43add3c34c889102Chiao Cheng 275273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 276273399bf829133a8385332ad43add3c34c889102Chiao Cheng protected int getViewGroupLabelResId() { 277273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mViewGroupLabelResId; 278273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 279273399bf829133a8385332ad43add3c34c889102Chiao Cheng 280273399bf829133a8385332ad43add3c34c889102Chiao Cheng @Override 281273399bf829133a8385332ad43add3c34c889102Chiao Cheng public List<String> getExtensionPackageNames() { 282273399bf829133a8385332ad43add3c34c889102Chiao Cheng return mExtensionPackageNames; 283273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 284273399bf829133a8385332ad43add3c34c889102Chiao Cheng 285273399bf829133a8385332ad43add3c34c889102Chiao Cheng /** 286273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Inflate this {@link AccountType} from the given parser. This may only 287273399bf829133a8385332ad43add3c34c889102Chiao Cheng * load details matching the publicly-defined schema. 288273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 289273399bf829133a8385332ad43add3c34c889102Chiao Cheng protected void inflate(Context context, XmlPullParser parser) throws DefinitionException { 290273399bf829133a8385332ad43add3c34c889102Chiao Cheng final AttributeSet attrs = Xml.asAttributeSet(parser); 291273399bf829133a8385332ad43add3c34c889102Chiao Cheng 292273399bf829133a8385332ad43add3c34c889102Chiao Cheng try { 293273399bf829133a8385332ad43add3c34c889102Chiao Cheng int type; 294273399bf829133a8385332ad43add3c34c889102Chiao Cheng while ((type = parser.next()) != XmlPullParser.START_TAG 295273399bf829133a8385332ad43add3c34c889102Chiao Cheng && type != XmlPullParser.END_DOCUMENT) { 296273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Drain comments and whitespace 297273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 298273399bf829133a8385332ad43add3c34c889102Chiao Cheng 299273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (type != XmlPullParser.START_TAG) { 300273399bf829133a8385332ad43add3c34c889102Chiao Cheng throw new IllegalStateException("No start tag found"); 301273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 302273399bf829133a8385332ad43add3c34c889102Chiao Cheng 303273399bf829133a8385332ad43add3c34c889102Chiao Cheng String rootTag = parser.getName(); 304273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (!TAG_CONTACTS_ACCOUNT_TYPE.equals(rootTag) && 305273399bf829133a8385332ad43add3c34c889102Chiao Cheng !TAG_CONTACTS_SOURCE_LEGACY.equals(rootTag)) { 306273399bf829133a8385332ad43add3c34c889102Chiao Cheng throw new IllegalStateException("Top level element must be " 307273399bf829133a8385332ad43add3c34c889102Chiao Cheng + TAG_CONTACTS_ACCOUNT_TYPE + ", not " + rootTag); 308273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 309273399bf829133a8385332ad43add3c34c889102Chiao Cheng 310273399bf829133a8385332ad43add3c34c889102Chiao Cheng mHasContactsMetadata = true; 311273399bf829133a8385332ad43add3c34c889102Chiao Cheng 312273399bf829133a8385332ad43add3c34c889102Chiao Cheng int attributeCount = parser.getAttributeCount(); 313273399bf829133a8385332ad43add3c34c889102Chiao Cheng for (int i = 0; i < attributeCount; i++) { 314273399bf829133a8385332ad43add3c34c889102Chiao Cheng String attr = parser.getAttributeName(i); 315273399bf829133a8385332ad43add3c34c889102Chiao Cheng String value = parser.getAttributeValue(i); 316273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (Log.isLoggable(TAG, Log.DEBUG)) { 317273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.d(TAG, attr + "=" + value); 318273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 319273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (ATTR_EDIT_CONTACT_ACTIVITY.equals(attr)) { 320273399bf829133a8385332ad43add3c34c889102Chiao Cheng mEditContactActivityClassName = value; 321273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_CREATE_CONTACT_ACTIVITY.equals(attr)) { 322273399bf829133a8385332ad43add3c34c889102Chiao Cheng mCreateContactActivityClassName = value; 323273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_INVITE_CONTACT_ACTIVITY.equals(attr)) { 324273399bf829133a8385332ad43add3c34c889102Chiao Cheng mInviteContactActivity = value; 325273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_INVITE_CONTACT_ACTION_LABEL.equals(attr)) { 326273399bf829133a8385332ad43add3c34c889102Chiao Cheng mInviteActionLabelAttribute = value; 327273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_VIEW_CONTACT_NOTIFY_SERVICE.equals(attr)) { 328273399bf829133a8385332ad43add3c34c889102Chiao Cheng mViewContactNotifyService = value; 329273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_VIEW_GROUP_ACTIVITY.equals(attr)) { 330273399bf829133a8385332ad43add3c34c889102Chiao Cheng mViewGroupActivity = value; 331273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_VIEW_GROUP_ACTION_LABEL.equals(attr)) { 332273399bf829133a8385332ad43add3c34c889102Chiao Cheng mViewGroupLabelAttribute = value; 333273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_DATA_SET.equals(attr)) { 334273399bf829133a8385332ad43add3c34c889102Chiao Cheng dataSet = value; 335273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_EXTENSION_PACKAGE_NAMES.equals(attr)) { 336273399bf829133a8385332ad43add3c34c889102Chiao Cheng mExtensionPackageNames.add(value); 337273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_ACCOUNT_TYPE.equals(attr)) { 338273399bf829133a8385332ad43add3c34c889102Chiao Cheng accountType = value; 339273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_ACCOUNT_LABEL.equals(attr)) { 340273399bf829133a8385332ad43add3c34c889102Chiao Cheng mAccountTypeLabelAttribute = value; 341273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (ATTR_ACCOUNT_ICON.equals(attr)) { 342273399bf829133a8385332ad43add3c34c889102Chiao Cheng mAccountTypeIconAttribute = value; 343273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else { 344273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.e(TAG, "Unsupported attribute " + attr); 345273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 346273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 347273399bf829133a8385332ad43add3c34c889102Chiao Cheng 348273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Parse all children kinds 349273399bf829133a8385332ad43add3c34c889102Chiao Cheng final int startDepth = parser.getDepth(); 350273399bf829133a8385332ad43add3c34c889102Chiao Cheng while (((type = parser.next()) != XmlPullParser.END_TAG 351273399bf829133a8385332ad43add3c34c889102Chiao Cheng || parser.getDepth() > startDepth) 352273399bf829133a8385332ad43add3c34c889102Chiao Cheng && type != XmlPullParser.END_DOCUMENT) { 353273399bf829133a8385332ad43add3c34c889102Chiao Cheng 354273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (type != XmlPullParser.START_TAG || parser.getDepth() != startDepth + 1) { 355273399bf829133a8385332ad43add3c34c889102Chiao Cheng continue; // Not a direct child tag 356273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 357273399bf829133a8385332ad43add3c34c889102Chiao Cheng 358273399bf829133a8385332ad43add3c34c889102Chiao Cheng String tag = parser.getName(); 359273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (TAG_EDIT_SCHEMA.equals(tag)) { 360273399bf829133a8385332ad43add3c34c889102Chiao Cheng mHasEditSchema = true; 361273399bf829133a8385332ad43add3c34c889102Chiao Cheng parseEditSchema(context, parser, attrs); 362273399bf829133a8385332ad43add3c34c889102Chiao Cheng } else if (TAG_CONTACTS_DATA_KIND.equals(tag)) { 363273399bf829133a8385332ad43add3c34c889102Chiao Cheng final TypedArray a = context.obtainStyledAttributes(attrs, 3643aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind); 365273399bf829133a8385332ad43add3c34c889102Chiao Cheng final DataKind kind = new DataKind(); 366273399bf829133a8385332ad43add3c34c889102Chiao Cheng 367273399bf829133a8385332ad43add3c34c889102Chiao Cheng kind.mimeType = a 3683aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee .getString(R.styleable.ContactsDataKind_android_mimeType); 369273399bf829133a8385332ad43add3c34c889102Chiao Cheng final String summaryColumn = a.getString( 3703aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind_android_summaryColumn); 371273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (summaryColumn != null) { 372273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Inflate a specific column as summary when requested 373273399bf829133a8385332ad43add3c34c889102Chiao Cheng kind.actionHeader = new SimpleInflater(summaryColumn); 374273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 375273399bf829133a8385332ad43add3c34c889102Chiao Cheng final String detailColumn = a.getString( 3763aa2cb56ece8461f2df69d9300c9a1abf03f6989Yorke Lee R.styleable.ContactsDataKind_android_detailColumn); 377273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (detailColumn != null) { 378273399bf829133a8385332ad43add3c34c889102Chiao Cheng // Inflate specific column as summary 379273399bf829133a8385332ad43add3c34c889102Chiao Cheng kind.actionBody = new SimpleInflater(detailColumn); 380273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 381273399bf829133a8385332ad43add3c34c889102Chiao Cheng 382273399bf829133a8385332ad43add3c34c889102Chiao Cheng a.recycle(); 383273399bf829133a8385332ad43add3c34c889102Chiao Cheng 384273399bf829133a8385332ad43add3c34c889102Chiao Cheng addKind(kind); 385273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 386273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 387273399bf829133a8385332ad43add3c34c889102Chiao Cheng } catch (XmlPullParserException e) { 388273399bf829133a8385332ad43add3c34c889102Chiao Cheng throw new DefinitionException("Problem reading XML", e); 389273399bf829133a8385332ad43add3c34c889102Chiao Cheng } catch (IOException e) { 390273399bf829133a8385332ad43add3c34c889102Chiao Cheng throw new DefinitionException("Problem reading XML", e); 391273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 392273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 393273399bf829133a8385332ad43add3c34c889102Chiao Cheng 394273399bf829133a8385332ad43add3c34c889102Chiao Cheng /** 395273399bf829133a8385332ad43add3c34c889102Chiao Cheng * Takes a string in the "@xxx/yyy" format and return the resource ID for the resource in 396273399bf829133a8385332ad43add3c34c889102Chiao Cheng * the resource package. 397273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 398273399bf829133a8385332ad43add3c34c889102Chiao Cheng * If the argument is in the invalid format or isn't a resource name, it returns -1. 399273399bf829133a8385332ad43add3c34c889102Chiao Cheng * 400273399bf829133a8385332ad43add3c34c889102Chiao Cheng * @param context context 401273399bf829133a8385332ad43add3c34c889102Chiao Cheng * @param resourceName Resource name in the "@xxx/yyy" format, e.g. "@string/invite_lavbel" 402273399bf829133a8385332ad43add3c34c889102Chiao Cheng * @param packageName name of the package containing the resource. 403273399bf829133a8385332ad43add3c34c889102Chiao Cheng * @param xmlAttributeName attribute name which the resource came from. Used for logging. 404273399bf829133a8385332ad43add3c34c889102Chiao Cheng */ 405273399bf829133a8385332ad43add3c34c889102Chiao Cheng @VisibleForTesting 406273399bf829133a8385332ad43add3c34c889102Chiao Cheng static int resolveExternalResId(Context context, String resourceName, 407273399bf829133a8385332ad43add3c34c889102Chiao Cheng String packageName, String xmlAttributeName) { 408273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (TextUtils.isEmpty(resourceName)) { 409273399bf829133a8385332ad43add3c34c889102Chiao Cheng return -1; // Empty text is okay. 410273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 411273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (resourceName.charAt(0) != '@') { 412273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.e(TAG, xmlAttributeName + " must be a resource name beginnig with '@'"); 413273399bf829133a8385332ad43add3c34c889102Chiao Cheng return -1; 414273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 415273399bf829133a8385332ad43add3c34c889102Chiao Cheng final String name = resourceName.substring(1); 416273399bf829133a8385332ad43add3c34c889102Chiao Cheng final Resources res; 417273399bf829133a8385332ad43add3c34c889102Chiao Cheng try { 418273399bf829133a8385332ad43add3c34c889102Chiao Cheng res = context.getPackageManager().getResourcesForApplication(packageName); 419273399bf829133a8385332ad43add3c34c889102Chiao Cheng } catch (NameNotFoundException e) { 420273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.e(TAG, "Unable to load package " + packageName); 421273399bf829133a8385332ad43add3c34c889102Chiao Cheng return -1; 422273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 423273399bf829133a8385332ad43add3c34c889102Chiao Cheng final int resId = res.getIdentifier(name, null, packageName); 424273399bf829133a8385332ad43add3c34c889102Chiao Cheng if (resId == 0) { 425273399bf829133a8385332ad43add3c34c889102Chiao Cheng Log.e(TAG, "Unable to load " + resourceName + " from package " + packageName); 426273399bf829133a8385332ad43add3c34c889102Chiao Cheng return -1; 427273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 428273399bf829133a8385332ad43add3c34c889102Chiao Cheng return resId; 429273399bf829133a8385332ad43add3c34c889102Chiao Cheng } 430273399bf829133a8385332ad43add3c34c889102Chiao Cheng} 431