在我的同步适配器下面。在我添加StubAdapter(自动同步所需)之前,performSync
方法创建了联系人,我的应用程序标签。添加SubAdapter后,自动同步有效,但新创建的帐户不再显示应用程序图标,它们属于gmail帐户,而不是我的应用帐户。我在哪里犯了错误以及如何解决它?
SyncAdapter
public class ContactsSyncAdapterService extends Service {
private static SyncAdapterImpl sSyncAdapter = null;
public ContactsSyncAdapterService() {
super();
}
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
private Context mContext;
public SyncAdapterImpl(Context context) {
super(context, true);
mContext = context;
}
@Override public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
try {
ContactsSyncAdapterService.performSync(mContext, account, extras, authority, provider,
syncResult);
} catch (OperationCanceledException e) {
}
}
}
@Override public IBinder onBind(Intent intent) {
IBinder ret = null;
ret = getSyncAdapter().getSyncAdapterBinder();
return ret;
}
private SyncAdapterImpl getSyncAdapter() {
if (sSyncAdapter == null) sSyncAdapter = new SyncAdapterImpl(this);
return sSyncAdapter;
}
private static void performSync(Context context, Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) throws OperationCanceledException {
Cursor c = context.getContentResolver()
.query(addCallerIsSyncAdapterParameter(ContactsProvider.CONTENT_URI, true), null, null,
null, null);
context.getContentResolver()
.delete(addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI, true),
RawContacts.ACCOUNT_TYPE + " = ?", new String[] { "packgename" });
while (c.moveToNext()) {
ContactsManager.addContact(context, account, new MyContact(c));
}
c.close();
}
private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) {
if (isSyncOperation) {
return uri.buildUpon()
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
}
return uri;
}
}
添加联系功能
private static String MIMETYPE = "vnd.android.cursor.item/vnd.packagename.profile";
public static void addContact(Context context, Account account, MyContact contact) {
Log.e("mcheck", contact.toString());
ContentResolver resolver = context.getContentResolver();
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(
addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI, true))
.withValue(RawContacts.ACCOUNT_NAME, account.name).withValue(RawContacts.ACCOUNT_TYPE,
account.type)
//.withValue(RawContacts.SOURCE_ID, 12345)
//.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED)
.build());
ops.add(ContentProviderOperation.newInsert(
addCallerIsSyncAdapterParameter(Settings.CONTENT_URI, true))
.withValue(RawContacts.ACCOUNT_NAME, account.name)
.withValue(RawContacts.ACCOUNT_TYPE, account.type)
.withValue(Settings.UNGROUPED_VISIBLE, 1)
.build());
ops.add(
ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.DISPLAY_NAME, contact.name)
.build());
ops.add(
ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.phone)
.build());
ops.add(
ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Note.NOTE, contact.note)
.build());
if (!TextUtils.isEmpty(contact.email)) {
ops.add(ContentProviderOperation.newInsert(
addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.DATA, contact.email)
.build());
}
ops.add(
ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, MIMETYPE)
.withValue(Data.DATA1, contact.id)
.withValue(Data.DATA3, "Открыть профиль")
.build());
try {
ContentProviderResult[] results = resolver.applyBatch(ContactsContract.AUTHORITY, ops);
if (results.length == 0) ;
} catch (Exception e) {
e.printStackTrace();
}
}
private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) {
if (isSyncOperation) {
return uri.buildUpon()
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
}
return uri;
}
authenticator.xml
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="packgename"
android:icon="@drawable/ic_auth_sync"
android:smallIcon="@drawable/ic_auth_sync_small"
android:label="@string/app_name"
android:accountPreferences="@xml/account_preferences"
android:supportsUploading="false"/>
自定义联系人数据类型
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
<ContactsDataKind
android:icon="@drawable/ic_auth_sync"
android:mimeType="vnd.android.cursor.item/vnd.packgename.profile"
android:summaryColumn="data2"
android:detailColumn="data3"
/>
</ContactsSource>
同步adapter.xml
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="packgename"
android:supportsUploading="true"
android:contentAuthority="packgename.sync.provider"
android:isAlwaysSyncable="true"
android:userVisible="true"
/>
StubAdapter
public class StubProvider extends ContentProvider {
/*
* Always return true, indicating that the
* provider loaded correctly.
*/
@Override public boolean onCreate() {
return true;
}
/*
* Return no type for MIME type
*/
@Override public String getType(Uri uri) {
return null;
}
/*
* query() always returns no results
*
*/
@Override public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}
/*
* insert() always returns null (no URI)
*/
@Override public Uri insert(Uri uri, ContentValues values) {
return null;
}
/*
* delete() always returns "no rows affected" (0)
*/
@Override public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/*
* update() always returns "no rows affected" (0)
*/
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
身份验证
public class AccountAuthenticatorService extends Service {
private static final String TAG = "AccountSAS";
private static AccountAuthenticatorImpl sAccountAuthenticator = null;
public AccountAuthenticatorService() {
super();
}
@Override public IBinder onBind(Intent intent) {
IBinder ret = null;
if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
ret = getAuthenticator().getIBinder();
}
return ret;
}
private AccountAuthenticatorImpl getAuthenticator() {
if (sAccountAuthenticator == null) sAccountAuthenticator = new AccountAuthenticatorImpl(this);
return sAccountAuthenticator;
}
private static class AccountAuthenticatorImpl extends AbstractAccountAuthenticator {
private Context mContext;
public AccountAuthenticatorImpl(Context context) {
super(context);
mContext = context;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#addAccount(android.
* accounts.AccountAuthenticatorResponse, java.lang.String,
* java.lang.String, java.lang.String[], android.os.Bundle)
*/
@Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
String authTokenType, String[] requiredFeatures, Bundle options)
throws NetworkErrorException {
Bundle result = new Bundle();
Intent i = new Intent(mContext, packgename.view.activity.LoginActivity.class);
i.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
result.putParcelable(AccountManager.KEY_INTENT, i);
return result;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#confirmCredentials(
* android.accounts.AccountAuthenticatorResponse,
* android.accounts.Account, android.os.Bundle)
*/
@Override public Bundle confirmCredentials(AccountAuthenticatorResponse response,
Account account, Bundle options) {
// TODO Auto-generated method stub
Log.i(TAG, "confirmCredentials");
return null;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#editProperties(android
* .accounts.AccountAuthenticatorResponse, java.lang.String)
*/
@Override public Bundle editProperties(AccountAuthenticatorResponse response,
String accountType) {
// TODO Auto-generated method stub
Log.i(TAG, "editProperties");
return null;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#getAuthToken(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String, android.os.Bundle)
*/
@Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
String authTokenType, Bundle options) throws NetworkErrorException {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#getAuthTokenLabel(java
* .lang.String)
*/
@Override public String getAuthTokenLabel(String authTokenType) {
// TODO Auto-generated method stub
Log.i(TAG, "getAuthTokenLabel");
return null;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#hasFeatures(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String[])
*/
@Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
String[] features) throws NetworkErrorException {
// TODO Auto-generated method stub
Log.i(TAG, "hasFeatures: " + features);
return null;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#updateCredentials(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String, android.os.Bundle)
*/
@Override public Bundle updateCredentials(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle options) {
// TODO Auto-generated method stub
Log.i(TAG, "updateCredentials");
return null;
}
}
}