我正在将我的应用程序与android默认的联系人应用程序集成。我想在每个联系人详细信息中显示一个选项“ xyz using MyApp”。应用程序不与现有联系人合并,而是创建一个新联系人并在其中合并。
performSync()方法
data () {
return {
i: 0,
socialEvents: [
{name:'Musical show',location:'Colombo'},
{name:"DJ Party",location:'New york'},
{name:"Dinner dance",location:"Paris"}
]
}
},
created () {
setInterval (() =>{
this.i++
}, 15000)
},
computed: {
displayingEvent () {
return this.socialEvents[this.i % this.socialEvents.length]
}
}
答案 0 :(得分:3)
在您的addContact
代码中,您缺少告诉Contacts DB
将新的原始联系人加入现有联系人的部分,因此该联系人现在将包含您的原始联系人和您的应用-在通讯录应用中打开该联系人时会显示特定的行。
请查看有关如何将RawContact
加入现有联系人why won't contacts aggregate?
您可能需要将一些RawContact ID
传递给addContact方法,以便能够将两者结合在一起。
更新
让我们尝试将您的新原始联系人与 ALL 聚集在一起,而不是将聚合操作与您的RawContact
插入操作一起应用,我们尝试将其分为两个applyBatch
调用>现有的原始联系人,而不仅仅是其中之一。
尝试以下代码,确保将现有的联系人ID (不是原始联系人ID)和新的原始联系人ID 传递给它。
private void joinIntoExistingContact(long existingContactId, long newRawContactId) {
// get all existing raw-contact-ids that belong to the contact-id
List<Long> existingRawIds = new ArrayList<>();
Cursor cur = getContentResolver().query(RawContacts.CONTENT_URI, new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=" + existingContactId, null, null);
while (cur.moveToNext()) {
existingRawIds.add(cur.getLong(0));
}
cur.close();
Log.i("Join", "Found " + existingRawIds.size() + " raw-contact-ids");
List<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
// go over all existing raw ids, and join with our new one
for (Long existingRawId : existingRawIds) {
Builder builder = ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, newRawContactId);
builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, existingRawId);
ops.add(builder.build());
}
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
}
PS
不要打开两个duplicate questions,一个就足够了。
另一个更新
您似乎对ID感到有些困惑。
有Data
个ID,RawContact
个ID和Contact
个ID。
CommonDataKinds.Phone._ID
将返回一个Data
ID,标识存储电话号码的数据表中的特定行。
您也可以从Phone
表中获得其他ID,请使用:
CommonDataKinds.Phone.RAW_CONTACT_ID
CommonDataKinds.Phone.CONTACT_ID
您可以在此处了解更多信息: https://stackoverflow.com/a/50084029/819355
答案 1 :(得分:0)
在这里试试这对我来说是有效的代码
MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList<String> mNames = new ArrayList<>();
private ArrayList<String> mIDs = new ArrayList<>();
private ArrayList<String> mNumbers = new ArrayList<>();
@SuppressLint("StaticFieldLeak")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
} else {
// Retrieve names from phone's contact list and save in mNames
getContactDataBefore();
// Apply changes to phone's contact list
new AsyncTask<String, String, String>() {
@Override
protected String doInBackground(String... params) {
String name, number, id;
for (int i = 0; i < mIDs.size(); i++) {
// name = mNames.get(i);
id = mIDs.get(i);
number = mNumbers.get(i);
ContactsManager.addContact(MainActivity.this, new MyContact(id, number));
}
return null;
}
@Override
protected void onPostExecute(String s) {
getContactDataAfter();
}
}.execute();
}
}
private void getContactDataBefore() {
int i = 0;
// query all contact id's from device
Cursor c1 = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID}, null, null, null);
if ((c1 != null) && c1.moveToFirst()) {
do {
mIDs.add(c1.getString(c1.getColumnIndexOrThrow(ContactsContract.Contacts._ID)));
i++;
} while (c1.moveToNext() && i < c1.getCount());
c1.close();
}
getPhoneNumber();
}
private void getPhoneNumber(){
for (String data:mIDs){
Cursor cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{data}, null);
while (cursor.moveToNext())
{
mNumbers.add(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
}
cursor.close();
}
}
/**
* Method to fetch contacts after updation (for logging purposes)
*/
private void getContactDataAfter() {
Cursor c = getContentResolver()
.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
List<String> RIds = new ArrayList<>();
mIDs = new ArrayList<>();
mNumbers = new ArrayList<>();
int i = 0;
if (c != null && c.moveToFirst()) {
do {
mIDs.add(c.getString(c
.getColumnIndexOrThrow(ContactsContract.Contacts._ID)));
mNames.add(c.getString(c
.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)));
Cursor c2 = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
new String[]{mIDs.get(i)}, null);
if (c2 != null && c2.moveToFirst()) {
do {
mNumbers.add(c2.getString(c2
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)));
} while (c2.moveToNext());
c2.close();
}
Cursor rawcontacts = getContentResolver()
.query(ContactsContract.RawContacts.CONTENT_URI,
new String[]{ContactsContract.RawContacts._ID},
ContactsContract.RawContacts.CONTACT_ID + "=?",
new String[]{mIDs.get(i)}, null);
if (rawcontacts != null && rawcontacts.moveToFirst()) {
do {
RIds.add(rawcontacts.getString(rawcontacts
.getColumnIndexOrThrow(ContactsContract.RawContacts._ID)));
} while (rawcontacts.moveToNext());
rawcontacts.close();
}
i++;
} while (c.moveToNext());
c.close();
}
}
}
AuthenticatorActivity
public class AuthenticatorActivity extends AccountAuthenticatorActivity {
private AccountManager mAccountManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_authenticator);
Intent res = new Intent();
res.putExtra(AccountManager.KEY_ACCOUNT_NAME, Constants.ACCOUNT_NAME);
res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
res.putExtra(AccountManager.KEY_AUTHTOKEN, Constants.ACCOUNT_TOKEN);
Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
mAccountManager = AccountManager.get(this);
mAccountManager.addAccountExplicitly(account, null, null);
// mAccountManager.setAuthToken(account, Constants.AUTHTOKEN_TYPE_FULL_ACCESS, Constants.ACCOUNT_TOKEN);
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
setAccountAuthenticatorResult(res.getExtras());
setResult(RESULT_OK, res);
finish();
}
}
SyncAdapter
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private Context mContext;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContext = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
}
}
SyncService
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter mSyncAdapter = null;
@Override
public void onCreate() {
synchronized (sSyncAdapterLock){
if(mSyncAdapter == null){
mSyncAdapter = new SyncAdapter(getApplicationContext(),true);
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mSyncAdapter.getSyncAdapterBinder();
}
}
AuthenticationService
public class AuthenticationService extends Service {
private static final String TAG = "AuthenticationService";
private Authenticator mAuthenticator;
@Override
public void onCreate() {
if (android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE)) {
android.util.Log.v(TAG, "SyncAdapter Authentication Service started.");
}
mAuthenticator = new Authenticator(this);
}
@Override
public void onDestroy() {
if (android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE)) {
Log.v(TAG, "SyncAdapter Authentication Service stopped.");
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getBinder()... returning the AccountAuthenticator binder for intent "
+ intent);
}
return mAuthenticator.getIBinder();
}
}
身份验证者
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, AuthenticatorActivity.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, 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;
}
}
常量
public class Constants {
public static final String ACCOUNT_TYPE = "com.example.ajay.contacts_4";
public static final String ACCOUNT_NAME = "Nilesh_Rathod";
public static final String ACCOUNT_TOKEN = "733N";
}
ContactsManager
public class ContactsManager {
private static String MIMETYPE = "vnd.android.cursor.item/com.example.ajay.contacts_4";
public static void addContact(Context context, MyContact contact) {
ContentResolver resolver = context.getContentResolver();
boolean mHasAccount = isAlreadyRegistered(resolver, contact.Id);
if (mHasAccount) {
Log.I("Account is Exist");
} else {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
// insert account name and account type
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.RawContacts.CONTENT_URI, true))
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE,
ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.build());
// insert contact number
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(CommonDataKinds.Phone.NUMBER, contact.number)
.build());
// insert mime-type data
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, "Nilesh")
.withValue(ContactsContract.Data.DATA3, "ContactsDemo")
.build());
}
}
/**
* Check if contact is already registered with app
*/
public static boolean isAlreadyRegistered(ContentResolver resolver, String id) {
boolean isRegistered = false;
List<String> str = new ArrayList<>();
//query raw contact id's from the contact id
Cursor c = resolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts._ID},
RawContacts.CONTACT_ID + "=?",
new String[]{id}, null);
//fetch all raw contact id's and save them in a list of string
if (c != null && c.moveToFirst()) {
do {
str.add(c.getString(c.getColumnIndexOrThrow(RawContacts._ID)));
} while (c.moveToNext());
c.close();
}
//query account types and check the account type for each raw contact id
for (int i = 0; i < str.size(); i++) {
Cursor c1 = resolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts.ACCOUNT_TYPE},
RawContacts._ID + "=?",
new String[]{str.get(i)}, null);
if (c1 != null) {
c1.moveToFirst();
String accType = c1.getString(c1.getColumnIndexOrThrow(RawContacts.ACCOUNT_TYPE));
if (accType != null && accType.equals("com.example.ajay.contacts_4")) {
isRegistered = true;
break;
}
c1.close();
}
}
return isRegistered;
}
/**
* Check for sync call
*/
private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) {
if (isSyncOperation) {
return uri.buildUpon()
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
}
return uri;
}
}
authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.example.ajay.contacts_4"
android:icon="@drawable/icon"
android:smallIcon="@drawable/icon"
android:label="@string/app_name" />
contacts.xml
<?xml version="1.0" encoding="utf-8"?>
<ContactsSource
xmlns:android="http://schemas.android.com/apk/res/android">
<ContactsDataKind
android:mimeType="vnd.android.cursor.item/com.example.ajay.contacts_4"
android:icon="@drawable/icon"
android:summaryColumn="data2"
android:detailColumn="data3" />
</ContactsSource>
syncadapter.xml
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.example.ajay.contacts_4"
android:supportsUploading="false"
android:userVisible="true" />
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="neel.com.contactssyncingapp">
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<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.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service android:name=".utils.AuthenticationService" >
<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=".sync.SyncService" >
<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>
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.ContactActivity"
android:label="ContactActivity"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/com.example.ajay.contacts_4" />
</intent-filter>
</activity>
<activity android:name=".activity.AuthenticatorActivity" />
</application>
</manifest>
输出
更新
public class ContactActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact);
Uri intentData = getIntent().getData();
if (!Uri.EMPTY.equals(intentData))
{
Cursor cursor = getContentResolver().query(intentData, null, null, null, null);
if (cursor.moveToNext())
{
String username = cursor.getString(cursor.getColumnIndex("data2"));
String number = cursor.getString(cursor.getColumnIndex("data3"));
Log.e("USER_NAME",username);
Log.e("USER_NUMBER",number);
}
}
}
}