/* * 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.contacts.common.model.account; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; import com.android.contacts.common.R; import com.android.contacts.common.model.dataitem.DataKind; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; /** A general contacts account type descriptor. */ public class ExternalAccountType extends BaseAccountType { private static final String TAG = "ExternalAccountType"; private static final String SYNC_META_DATA = "android.content.SyncAdapter"; /** * The metadata name for so-called "contacts.xml". * *
On LMP and later, we also accept the "alternate" name. This is to allow sync adapters to
* have a contacts.xml without making it visible on older platforms. If you modify this also
* update the corresponding list in ContactsProvider/PhotoPriorityResolver
*/
private static final String[] METADATA_CONTACTS_NAMES =
new String[] {
"android.provider.ALTERNATE_CONTACTS_STRUCTURE", "android.provider.CONTACTS_STRUCTURE"
};
private static final String TAG_CONTACTS_SOURCE_LEGACY = "ContactsSource";
private static final String TAG_CONTACTS_ACCOUNT_TYPE = "ContactsAccountType";
private static final String TAG_CONTACTS_DATA_KIND = "ContactsDataKind";
private static final String TAG_EDIT_SCHEMA = "EditSchema";
private static final String ATTR_EDIT_CONTACT_ACTIVITY = "editContactActivity";
private static final String ATTR_CREATE_CONTACT_ACTIVITY = "createContactActivity";
private static final String ATTR_INVITE_CONTACT_ACTIVITY = "inviteContactActivity";
private static final String ATTR_INVITE_CONTACT_ACTION_LABEL = "inviteContactActionLabel";
private static final String ATTR_VIEW_CONTACT_NOTIFY_SERVICE = "viewContactNotifyService";
private static final String ATTR_VIEW_GROUP_ACTIVITY = "viewGroupActivity";
private static final String ATTR_VIEW_GROUP_ACTION_LABEL = "viewGroupActionLabel";
private static final String ATTR_DATA_SET = "dataSet";
private static final String ATTR_EXTENSION_PACKAGE_NAMES = "extensionPackageNames";
// The following attributes should only be set in non-sync-adapter account types. They allow
// for the account type and resource IDs to be specified without an associated authenticator.
private static final String ATTR_ACCOUNT_TYPE = "accountType";
private static final String ATTR_ACCOUNT_LABEL = "accountTypeLabel";
private static final String ATTR_ACCOUNT_ICON = "accountTypeIcon";
private final boolean mIsExtension;
private String mEditContactActivityClassName;
private String mCreateContactActivityClassName;
private String mInviteContactActivity;
private String mInviteActionLabelAttribute;
private int mInviteActionLabelResId;
private String mViewContactNotifyService;
private String mViewGroupActivity;
private String mViewGroupLabelAttribute;
private int mViewGroupLabelResId;
private List This method looks through all services in the package that handle sync adapter intents for
* the first one that contains CONTACTS_STRUCTURE metadata. We have to look through all sync
* adapters in the package in case there are contacts and other sync adapters (eg, calendar) in
* the same package.
*
* Returns {@code null} if the package has no CONTACTS_STRUCTURE metadata. In this case the
* account type *will* be initialized with minimal configuration.
*/
public static XmlResourceParser loadContactsXml(Context context, String resPackageName) {
final PackageManager pm = context.getPackageManager();
final Intent intent = new Intent(SYNC_META_DATA).setPackage(resPackageName);
final List If the argument is in the invalid format or isn't a resource name, it returns -1.
*
* @param context context
* @param resourceName Resource name in the "@xxx/yyy" format, e.g. "@string/invite_lavbel"
* @param packageName name of the package containing the resource.
* @param xmlAttributeName attribute name which the resource came from. Used for logging.
*/
@VisibleForTesting
static int resolveExternalResId(
Context context, String resourceName, String packageName, String xmlAttributeName) {
if (TextUtils.isEmpty(resourceName)) {
return -1; // Empty text is okay.
}
if (resourceName.charAt(0) != '@') {
Log.e(TAG, xmlAttributeName + " must be a resource name beginnig with '@'");
return -1;
}
final String name = resourceName.substring(1);
final Resources res;
try {
res = context.getPackageManager().getResourcesForApplication(packageName);
} catch (NameNotFoundException e) {
Log.e(TAG, "Unable to load package " + packageName);
return -1;
}
final int resId = res.getIdentifier(name, null, packageName);
if (resId == 0) {
Log.e(TAG, "Unable to load " + resourceName + " from package " + packageName);
return -1;
}
return resId;
}
private void checkKindExists(String mimeType) throws DefinitionException {
if (getKindForMimetype(mimeType) == null) {
throw new DefinitionException(mimeType + " must be supported");
}
}
@Override
public boolean isEmbedded() {
return false;
}
@Override
public boolean isExtension() {
return mIsExtension;
}
@Override
public boolean areContactsWritable() {
return mHasEditSchema;
}
/** Whether this account type has the android.provider.CONTACTS_STRUCTURE metadata xml. */
public boolean hasContactsMetadata() {
return mHasContactsMetadata;
}
@Override
public String getEditContactActivityClassName() {
return mEditContactActivityClassName;
}
@Override
public String getCreateContactActivityClassName() {
return mCreateContactActivityClassName;
}
@Override
public String getInviteContactActivityClassName() {
return mInviteContactActivity;
}
@Override
protected int getInviteContactActionResId() {
return mInviteActionLabelResId;
}
@Override
public String getViewContactNotifyServiceClassName() {
return mViewContactNotifyService;
}
@Override
public String getViewGroupActivity() {
return mViewGroupActivity;
}
@Override
protected int getViewGroupLabelResId() {
return mViewGroupLabelResId;
}
@Override
public List