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