/* * 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.ContentValues; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.RawContacts; import android.support.annotation.VisibleForTesting; import android.support.v4.content.ContextCompat; import android.util.ArrayMap; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import com.android.contacts.common.R; import com.android.contacts.common.model.dataitem.DataKind; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; /** * Internal structure that represents constraints and styles for a specific data source, such as the * various data types they support, including details on how those types should be rendered and * edited. * *
In the future this may be inflated from XML defined by a data source.
*/
public abstract class AccountType {
private static final String TAG = "AccountType";
/** {@link Comparator} to sort by {@link DataKind#weight}. */
private static Comparator TODO Clean up {@link #resourcePackageName}, {@link #syncAdapterPackageName} and {@link
* #getViewContactNotifyServicePackageName()}.
*
* There's the following invariants: - {@link #syncAdapterPackageName} is always set to the
* actual sync adapter package name. - {@link #resourcePackageName} too is set to the same value,
* unless {@link #isEmbedded()}, in which case it'll be null. There's an unfortunate exception of
* {@link FallbackAccountType}. Even though it {@link #isEmbedded()}, but we set non-null to
* {@link #resourcePackageName} for unit tests.
*/
public String resourcePackageName;
/**
* The package name for the authenticator (for the embedded types, i.e. Google and Exchange) or
* the sync adapter (for external type, including extensions).
*/
public String syncAdapterPackageName;
public int titleRes;
public int iconRes;
protected boolean mIsInitialized;
/** Set of {@link DataKind} supported by this source. */
private ArrayList (The behavior is undefined if the resource or package doesn't exist.)
*/
@VisibleForTesting
static CharSequence getResourceText(
Context context, String packageName, int resId, String defaultValue) {
if (resId != -1 && packageName != null) {
final PackageManager pm = context.getPackageManager();
return pm.getText(packageName, resId, null);
} else if (resId != -1) {
return context.getText(resId);
} else {
return defaultValue;
}
}
public static Drawable getDisplayIcon(
Context context, int titleRes, int iconRes, String syncAdapterPackageName) {
if (titleRes != -1 && syncAdapterPackageName != null) {
final PackageManager pm = context.getPackageManager();
return pm.getDrawable(syncAdapterPackageName, iconRes, null);
} else if (titleRes != -1) {
return ContextCompat.getDrawable(context, iconRes);
} else {
return null;
}
}
/**
* Whether this account type was able to be fully initialized. This may be false if (for example)
* the package name associated with the account type could not be found.
*/
public final boolean isInitialized() {
return mIsInitialized;
}
/**
* @return Whether this type is an "embedded" type. i.e. any of {@link FallbackAccountType},
* {@link GoogleAccountType} or {@link ExternalAccountType}.
* If an embedded type cannot be initialized (i.e. if {@link #isInitialized()} returns
* {@code false}) it's considered critical, and the application will crash. On the other hand
* if it's not an embedded type, we just skip loading the type.
*/
public boolean isEmbedded() {
return true;
}
public boolean isExtension() {
return false;
}
/**
* @return True if contacts can be created and edited using this app. If false, there could still
* be an external editor as provided by {@link #getEditContactActivityClassName()} or {@link
* #getCreateContactActivityClassName()}
*/
public abstract boolean areContactsWritable();
/**
* Returns an optional custom edit activity.
*
* Only makes sense for non-embedded account types. The activity class should reside in the
* sync adapter package as determined by {@link #syncAdapterPackageName}.
*/
public String getEditContactActivityClassName() {
return null;
}
/**
* Returns an optional custom new contact activity.
*
* Only makes sense for non-embedded account types. The activity class should reside in the
* sync adapter package as determined by {@link #syncAdapterPackageName}.
*/
public String getCreateContactActivityClassName() {
return null;
}
/**
* Returns an optional custom invite contact activity.
*
* Only makes sense for non-embedded account types. The activity class should reside in the
* sync adapter package as determined by {@link #syncAdapterPackageName}.
*/
public String getInviteContactActivityClassName() {
return null;
}
/**
* Returns an optional service that can be launched whenever a contact is being looked at. This
* allows the sync adapter to provide more up-to-date information.
*
* The service class should reside in the sync adapter package as determined by {@link
* #getViewContactNotifyServicePackageName()}.
*/
public String getViewContactNotifyServiceClassName() {
return null;
}
/**
* TODO This is way too hacky should be removed.
*
* This is introduced for {@link GoogleAccountType} where {@link #syncAdapterPackageName} is
* the authenticator package name but the notification service is in the sync adapter package. See
* {@link #resourcePackageName} -- we should clean up those.
*/
public String getViewContactNotifyServicePackageName() {
return syncAdapterPackageName;
}
/** Returns an optional Activity string that can be used to view the group. */
public String getViewGroupActivity() {
return null;
}
public CharSequence getDisplayLabel(Context context) {
// Note this resource is defined in the sync adapter package, not resourcePackageName.
return getResourceText(context, syncAdapterPackageName, titleRes, accountType);
}
/** @return resource ID for the "invite contact" action label, or -1 if not defined. */
protected int getInviteContactActionResId() {
return -1;
}
/** @return resource ID for the "view group" label, or -1 if not defined. */
protected int getViewGroupLabelResId() {
return -1;
}
/** Returns {@link AccountTypeWithDataSet} for this type. */
public AccountTypeWithDataSet getAccountTypeAndDataSet() {
return AccountTypeWithDataSet.get(accountType, dataSet);
}
/**
* Returns a list of additional package names that should be inspected as additional external
* account types. This allows for a primary account type to indicate other packages that may not
* be sync adapters but which still provide contact data, perhaps under a separate data set within
* the account.
*/
public List