求助:如何通过SyncAdapter在联系人详情页显示应用名称与图标

我想实现类似WhatsApp的效果,在用户的联系人详情页面显示我的应用名称和图标,于是尝试用SyncAdapter来实现,但没得到预期结果。以下是我的相关代码,恳请各位开发者帮忙排查问题:
Authenticator 类
public class Authenticator extends AbstractAccountAuthenticator { private final Context mContext; public Authenticator(Context context) { super(context); mContext = context; } @Override public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { return null; } @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { final Intent intent = new Intent(mContext, MainActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } @Override public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { return null; } @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, SyncStateContract.Constants.ACCOUNT_TYPE); return result; } @Override public String getAuthTokenLabel(String authTokenType) { return null; } @Override public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { return null; } @Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { return null; } }
AuthenticatorService 类
public class AuthenticatorService extends Service { private Authenticator authenticator; @Override public void onCreate() { authenticator = new Authenticator(this); } /* * 当系统绑定到该服务进行RPC调用时,返回认证器的IBinder */ @Override public IBinder onBind(Intent intent) { return authenticator.getIBinder(); } }
ContactManager 类
public class ContactsManager { private static String MIMETYPE = "vnd.android.cursor.item/com.example.syncadapter"; public static void addContact(Context context,MyContact contact){ ContentResolver resolver = context.getContentResolver(); ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); ops.add(ContentProviderOperation .newInsert(addCallerIsSyncAdapterParameter( ContactsContract.RawContacts.CONTENT_URI, true)) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, SyncStateContract.Constants.ACCOUNT_NAME) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, SyncStateContract.Constants.ACCOUNT_TYPE) .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT) .build()); ops.add(ContentProviderOperation .newInsert(addCallerIsSyncAdapterParameter( ContactsContract.Data.CONTENT_URI, true)) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.name) .build()); ops.add(ContentProviderOperation .newInsert(addCallerIsSyncAdapterParameter( ContactsContract.Data.CONTENT_URI, true)) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,0) .withValue(ContactsContract.Data.MIMETYPE, MIMETYPE) .withValue(ContactsContract.Data.DATA1, 12345) .withValue(ContactsContract.Data.DATA2, "user") .withValue(ContactsContract.Data.DATA3, "MyData") .build()); try { resolver.applyBatch(ContactsContract.AUTHORITY, ops); } 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; } }
MainActivity 类
public class MainActivity extends AppCompatActivity { private ArrayList<String> mNames = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 从手机联系人列表中获取姓名并保存到mNames getNames(); // 对手机联系人列表进行修改 new Thread(new Runnable() { @Override public void run() { String name; for(int i=0;i<mNames.size();i++){ name = mNames.get(i); ContactsManager.addContact(MainActivity.this, new MyContact(name)); } } }).start(); } private void getNames(){ int hasPhone; Cursor c = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,null,null,null); if((c != null) && c.moveToFirst()){ while(c.moveToNext()){ hasPhone = Integer.parseInt(c.getString( c.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER))); if(hasPhone == 1) mNames.add(c.getString( c.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))); } c.close(); } } }
MyContact 类(用于封装联系人姓名)
public class MyContact { String name; public MyContact(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MyContact)) return false; MyContact myContact = (MyContact) o; return Objects.equals(name, myContact.name); } @Override public int hashCode() { return Objects.hash(name); } }
SyncAdapter 类
public class SyncAdapter extends AbstractThreadedSyncAdapter { public SyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); Log.d("sync adapter","同步适配器已创建。"); } @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { Log.d("sync adapter","同步适配器已调用。"); } }
SyncService 类
public class SyncService extends Service { private static final Object sSyncAdapterLock = new Object(); private static SyncAdapter mSyncAdapter = null; @Override public void onCreate() { Log.d("sync adapter","同步服务已创建。"); synchronized (sSyncAdapterLock){ if(mSyncAdapter == null){ mSyncAdapter = new SyncAdapter(getApplicationContext(), true); } } } @Nullable @Override public IBinder onBind(Intent intent) { Log.d("sync adapter","同步服务已绑定。"); return mSyncAdapter.getSyncAdapterBinder(); } }
Authenticator 配置文件(res/xml/authenticator.xml)
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="com.example.ajay.contacts_4" android:icon="@mipmap/ic_launcher" android:smallIcon="@mipmap/ic_launcher" android:label="@string/app_name" />
联系人结构配置文件(res/xml/contacts.xml)
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> <ContactsDataKind android:mimeType="vnd.android.cursor.item/com.example.syncadapter.message" android:icon="@mipmap/ic_launcher" android:summaryColumn="data2" android:detailColumn="data3"/> <ContactsDataKind android:mimeType="vnd.android.cursor.item/com.example.syncadapter.voice" android:icon="@mipmap/ic_launcher" android:summaryColumn="data2" android:detailColumn="data3"/> <ContactsDataKind android:mimeType="vnd.android.cursor.item/com.example.syncadapter.video" android:icon="@mipmap/ic_launcher" android:summaryColumn="data2" android:detailColumn="data3"/> </ContactsAccountType>
SyncAdapter 配置文件(res/xml/syncadapter.xml)
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.android.contacts" android:accountType="com.example.syncadapter" android:supportsUploading="false" android:userVisible="true"/>
AndroidManifest.xml 配置文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.syncadapter"> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.SyncAdapter" tools:targetApi="31"> <activity android:name=".AuthenticatorActivity" android:exported="false" /> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <data android:mimeType="vnd.android.cursor.item/com.example.syncadapter.message" /> </intent-filter> </activity> <service android:name=".AuthenticatorService" tools:ignore="Instantiatable" android:exported="true"> <intent-filter> <action android:name="android.accounts.AccountAuthenticator" /> </intent-filter> <meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" /> </service> <service android:name=".SyncService" android:exported="true"> <intent-filter> <action android:name="android.content.SyncAdapter" /> </intent-filter> <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" /> <meta-data android:name="android.provider.CONTACTS_STRUCTURE" android:resource="@xml/contacts" /> </service> </application> </manifest>
内容的提问来源于stack exchange,提问作者NekoSenpai
相关产品推荐
相关产品推荐

