/* * CDDL HEADER START * * The contents of this file are subject to the terms of the Common Development * and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at * src/com/vodafone360/people/VODAFONE.LICENSE.txt or * http://github.com/360/360-Engine-for-Android * See the License for the specific language governing permissions and * limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each file and * include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the fields * enclosed by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved. * Use is subject to license terms. */ package com.vodafone360.people.engine.contactsync; import java.security.InvalidParameterException; import android.content.ContentResolver; import android.content.Context; import android.text.TextUtils; import com.vodafone360.people.utils.LogUtils; import com.vodafone360.people.utils.VersionUtils; /** * Class that provides an abstraction layer for accessing the Native Contacts API. * The underlying API to be used should be the most suitable for the SDK version of the device. */ public abstract class NativeContactsApi { /** * 360 client account type. */ protected static final int PEOPLE_ACCOUNT_TYPE = 1; /** * Google account type. */ protected static final int GOOGLE_ACCOUNT_TYPE = 2; /** * Vendor specific type. */ protected static final int PHONE_ACCOUNT_TYPE = 3; /** * Account type for 360 People in the Native Accounts. * MUST be a copy of type in 'res/xml/authenticator.xml' */ public static final String PEOPLE_ACCOUNT_TYPE_STRING = "com.vodafone360.people.android.account"; /** * Google account, there can be more than one of these */ protected static final String GOOGLE_ACCOUNT_TYPE_STRING = "com.google"; /** * HTC vendor specific account type for phone contacts. * Current indication is that this account type is HTC Sense specific. */ private static final String HTC_PHONE_ACCOUNT_TYPE_STRING = "com.htc.android.pcsc"; /** * Samsung vendor specific Account type String for phone contacts. */ private static final String SAMSUNG_PHONE_ACCOUNT_TYPE_STRING = "vnd.sec.contact.phone"; /** * Motorola vendor specific Account type String for phone contacts. * Current indication is that this account type is Moto Blur specific. */ private static final String MOTOROLA_PHONE_ACCOUNT_TYPE_STRING = "com.motorola.blur.service.bsutils.MOTHER_USER_CREDS_TYPE"; /** * Sony Ericsson vendor specific Account type for phone contacts. */ private static final String SONY_ERICSSON_PHONE_ACCOUNT_TYPE_STRING = "com.sonyericsson.localcontacts"; /** * There are devices with custom contact applications. For them we need * special handling of contacts. */ protected static final String[] VENDOR_SPECIFIC_ACCOUNTS = { HTC_PHONE_ACCOUNT_TYPE_STRING, SAMSUNG_PHONE_ACCOUNT_TYPE_STRING, MOTOROLA_PHONE_ACCOUNT_TYPE_STRING, SONY_ERICSSON_PHONE_ACCOUNT_TYPE_STRING }; /** * {@link NativeContactsApi} the singleton instance providing access to the correct Contacts API interface */ private static NativeContactsApi sInstance; /** * {@link Context} to be used by the Instance */ protected Context mContext; /** * {@link ContentResolver} be used by the Instance */ protected ContentResolver mCr; /** * Sadly have to have this so that only one organization may be read from a * NAB Contact */ protected boolean mHaveReadOrganization = false; /** * Sadly have to have this because Organization detail is split into two * details in CAB */ protected int mMarkedOrganizationIndex = -1; /** * Sadly have to have this because Organization detail is split into two * details in CAB */ protected int mMarkedTitleIndex = -1; /** * Create NativeContactsApi singleton instance for later usage. The instance * can retrieved by calling getInstance(). * The instance can be destroyed * by calling destroyInstance() * * @see NativeContactsApi#getInstance() * @see NativeContactsApi#destroyInstance() * @param context The context to be used by the singleton */ public static void createInstance(Context context) { LogUtils.logW("NativeContactsApi.createInstance()"); String className; if (VersionUtils.is2XPlatform()) { className = "NativeContactsApi2"; LogUtils.logD("Using 2.X Native Contacts API"); } else { className = "NativeContactsApi1"; LogUtils.logD("Using 1.X Native Contacts API"); } try { Class<? extends NativeContactsApi> clazz = Class.forName( NativeContactsApi.class.getPackage().getName() + "." + className).asSubclass( NativeContactsApi.class); sInstance = clazz.newInstance(); } catch (Exception e) { throw new IllegalStateException("NativeContactsApi.createInstance()" + "Error creating a subclass of NativeContactsApi", e); } sInstance.mContext = context; sInstance.mCr = context.getContentResolver(); // Initialize the instance now (got Context and Content Resolver) sInstance.initialize(); } /** * Destroy NativeContactsApi singleton instance if created. The instance can * be recreated by calling createInstance() * * @see NativeContactsApi#createInstance() */ public static void destroyInstance() { if (sInstance != null) { sInstance.mCr = null; sInstance.mContext = null; sInstance = null; } } /** * Retrieves singleton instance providing access to the native contacts api. * * @return {@link NativeContactsApi} appropriate subclass instantiation */ public static NativeContactsApi getInstance() { if (sInstance == null) { throw new InvalidParameterException("Please call " + "NativeContactsApi.createInstance() " + "before NativeContactsApi.getInstance()"); } return sInstance; } /** * This Account class represents an available account on the device where * the native synchronization can be performed. */ public static class Account { /** * The name of the account. */ private String mName; /** * The type of the account. */ private String mType; /** * The Constructor. * * @param name the account name * @param type the account type */ public Account(String name, String type) { mName = name; mType = type; } /** * Gets the name of the account. * * @return the account name */ public String getName() { return mName; } /** * Gets the type of the accounts. * * @return the account type */ public String getType() { return mType; } /** * Checks if this account is a People Account * * @return true if this account is a People Account, false if not */ public boolean isPeopleAccount() { return TextUtils.equals(mType, PEOPLE_ACCOUNT_TYPE_STRING); } /** * Returns a String representation of the account. */ public String toString() { return "Account: name=" + mName + ", type=" + mType; } } /** * The Observer interface to receive notifications about changes in the * native address book. */ public static interface ContactsObserver { /** * Call-back to notify that a change happened in the native address * book. */ void onChange(); } /** * Method meant to be called only just after createInstance() is invoked. * This method effectively acts as a replacement for the constructor because * of the use of reflection. */ protected abstract void initialize(); /** * Registers a content observer. Note: the method only supports one observer * at a time. * * @param observer ContactsObserver currently observing native address book * changes * @throws RuntimeException if a new observer is being registered without * having unregistered the previous one */ public abstract void registerObserver(ContactsObserver observer); /** * Unregister the previously registered content observer. */ public abstract void unregisterObserver(); /** * Fetches all the existing Accounts on the device. Only supported on 2.X. * The 1.X implementation always returns null. * * @return An array containing all the Accounts on the device, or null if * none exist */ public abstract Account[] getAccounts(); /** * Fetches all the existing Accounts on the device corresponding to the * provided Type Only supported on 2.X. The 1.X implementation always * returns null. * * @param type The Type of Account to fetch * @return An array containing all the Accounts of the provided Type, or * null if none exist */ public abstract Account[] getAccountsByType(int type); /** * Adds the currently logged in user account to the NAB accounts. Only * supported on 2.X. The 1.X implementation does nothing. * * @return true if successful, false if not */ public abstract boolean addPeopleAccount(String username); /** * Checks if there is a People Account in the NAB Accounts. Only supported * on 2.X The 1.X implementation does nothing. * * @return true if an account exists, false if not. */ public abstract boolean isPeopleAccountCreated(); /** * Removes the (first found) People Account from the NAB accounts. Only * supported on 2.X. The 1.X implementation does nothing. */ public abstract void removePeopleAccount(); /** * Retrieves a list of contact IDs for a specific account. In 1.X devices * only the null account is supported, i.e., a non null account always uses * null as a return value. * * @param account The account to get contact IDs from (may be null) * @return List of contact IDs from the native address book */ public abstract long[] getContactIds(Account account); /** * Gets data for one Contact. * * @param nabContactId Native ID for the contact * @return A {@link ContactChange} array with contact's data or null */ public abstract ContactChange[] getContact(long nabContactId); /** * Adds a contact. Note that the returned ID data will be the same size of * ccList plus one change containing the NAB Contact ID (at the first * position). The remaining IDs correspond to the details in the original * change list. Null IDs among these remaining IDs are possible when these * correspond to unsupported details. On 1.X Devices only a null account * parameter is expected. * * @param account Account to be associated with the added contact (may be * null). * @param ccList The Contact data as a {@link ContactChange} array * @return A {@link ContactChange} array with contact's new ID data or null * in case of failure. */ public abstract ContactChange[] addContact(Account account, ContactChange[] ccList); /** * Updates an existing contact. The returned ID data will be the same size * of the ccList. However, if a null or empty ccList is passed as an * argument then null is returned. Null IDs among the ID data are also * possible when these correspond to unsupported details. * * @param ccList The Contact update data as a {@link ContactChange} array * @return A {@link ContactChange} array with the contact's new ID data or * null */ public abstract ContactChange[] updateContact(ContactChange[] ccList); /** * Removes a contact * * @param nabContactId Native ID of the contact to remove */ public abstract void removeContact(long nabContactId); /** * Used to retrieve the master Auto-sync setting for the system. * Method only exists to get around platform fragmentation. * Note that this method always returns true for 1.X devices! * @return true if the Master Auto-sync is enabled, false otherwise */ public abstract boolean getMasterSyncAutomatically(); /** * Used to set the system syncable functionality on and off. * This is really only useful for 2.X devices. * @param syncable if true, false otherwise */ public abstract void setSyncable(boolean syncable); /** * Used to forcefully set the underlying Sync adapter to be Automatically Syncable or not. * This is really only useful for 2.X devices and for System UE. * @param syncAutomatically if true Sync is Automatic, false otherwise */ public abstract void setSyncAutomatically(boolean syncAutomatically); /** * Checks whether or not a {@link ContactChange} key is supported. Results * may vary in 1.X and 2.X * * @param key Key to check for support * @return true if supported, false if not */ public abstract boolean isKeySupported(int key); /** * Checks if this account is a vendor specific one. All vendor specific * accounts are held in the VENDOR_SPECIFIC_ACCOUNTS array. * * @param type to checks for * @return true if vendor specific account, false otherwise */ public boolean isVendorSpecificAccount(String type) { for (String vendorSpecificType : VENDOR_SPECIFIC_ACCOUNTS) { if (vendorSpecificType.equals(type)) { return true; } } return false; } }