I want to integrate my app with android default Contacts application just like Whatsapp,Paytm and TrueCaller is doing as shown in below screenshot.I would like to show an option "Recharge using MyApp" inside every Contacts Detail , clicking on which should open my app.I used below code through which I am able to see my app in Accounts Section with an option to sync Contacts but still my app is not showing in Contact detail page.The code adds a new contact rather than updating an existing contact.
I have added code for the implementation on github at this link.
Also i was following these tutorials- LINK1 LINK2
AccountAuthenticatorService
public class AccountAuthenticatorService extends Service {
private static final String TAG = "AccountAuthenticatorService";
private static AccountAuthenticatorImpl sAccountAuthenticator = null;
public AccountAuthenticatorService() {
super();
}
public IBinder onBind(Intent intent) {
IBinder ret = null;
if (intent.getAction().equals(android.accounts.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;
}
/*
* The user has requested to add a new account to the system. We return an intent that will launch our login screen if the user has not logged in yet,
* otherwise our activity will just pass the user's credentials on to the account manager.
*/
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options)
throws NetworkErrorException {
Bundle reply = new Bundle();
Intent i = new Intent(mContext, MainActivity.class);
reply.putParcelable(AccountManager.KEY_INTENT, i);
return reply;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) {
return null;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) {
return null;
}
}
}
LoginActivity
Account account = new Account("9958154991", "com.example.bhuvnesh.myapplication");
AccountManager am = AccountManager.get(this);
boolean accountCreated = am.addAccountExplicitly(account, null, null);
authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.example.bhuvnesh.myapplication"
android:icon="@mipmap/ic_launcher"
android:smallIcon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:accountPreferences="@xml/account_preference"/>
account_preference.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="General Settings" />
<PreferenceScreen
android:key="account_settings"
android:title="Account Settings"
android:summary="Sync frequency, notifications, etc.">
<intent
android:action="fm.last.android.activity.Preferences.ACCOUNT_SETUP"
android:targetPackage="fm.last.android"
android:targetClass="fm.last.android.activity.Preferences" />
</PreferenceScreen>
</PreferenceScreen>
ContactsSyncAdapterService.class
public class ContactsSyncAdapterService extends Service {
private static final String TAG = "ContactsSyncAdapter";
private static SyncAdapterImpl sSyncAdapter = null;
private static ContentResolver mContentResolver = 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 {
mContentResolver = context.getContentResolver();
Log.i(TAG, "performSync: " + account.toString());
//This is where the magic will happen!
}
}
sync_contacts.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.bhuvnesh.myapplication"/>
contacts.xml
<?xml version="1.0" encoding="utf-8"?>
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
<ContactsDataKind
android:icon="@mipmap/ic_launcher"
android:mimeType="vnd.android.cursor.item/vnd.com.example.bhuvnesh.myapplication.profile"
android:summaryColumn="data2"
android:detailColumn="data3"
android:detailSocialSummary="true" />
</ContactsSource>
performSync() method
private void insertIconinContacts() {
Cursor cursor = null;
String idContact , account;
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
int contactIdIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
int nameIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int phoneNumberIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int photoIdIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_ID);
int acc = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA);
cursor.moveToFirst();
do {
idContact = cursor.getString(contactIdIdx);
account = cursor.getString(acc);
// updateIMContactField(getContentResolver(), idContact, chooseClass);
addContact(getContentResolver(),nameIdx,phoneNumberIdx);
//...
} while (cursor.moveToNext());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
private static void addContact(ContentResolver contentResolver,int name, int phoneNumber) {
Log.i("BHUVNESH", "Adding contact: " + name);
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
//Create our RawContact
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI);
builder.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, name);
builder.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "com.example.bhuvnesh.myapplication");
builder.withValue(ContactsContract.RawContacts.SYNC1, phoneNumber);
operationList.add(builder.build());
//Create a Data record of common type 'StructuredName' for our RawContact
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
operationList.add(builder.build());
//Create a Data record of custom type "vnd.android.cursor.item/vnd.com.example.bhuvnesh.myapplication.profile" to display a link to the Last.fm profile
builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
builder.withValue(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.example.bhuvnesh.myapplication.profile");
builder.withValue(ContactsContract.Data.DATA1, phoneNumber);
builder.withValue(ContactsContract.Data.DATA2, "Last.fm Profile");
builder.withValue(ContactsContract.Data.DATA3, "View profile");
operationList.add(builder.build());
try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (Exception e) {
Log.e("BHUVNESH", "Something went wrong during creation! " + e);
e.printStackTrace();
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bhuvnesh.myapplication">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".service.AccountAuthenticatorService"
android:exported="true" android:process=":auth">
<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=".service.ContactsSyncAdapterService"
android:exported="true" android:process=":contacts">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/sync_contacts" />
<meta-data android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
</application>
</manifest>
UPDATE
As per @marmor answer ,I also tried adding below code inside addContact() but app not showing in contact detail screen
builder = ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI);
builder.withValue(ContactsContract.AggregationExceptions.TYPE, ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER);
builder.withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, id);
builder.withValueBackReference(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, 0);
operationList.add(builder.build());
from App added in Accounts with Contact sync option but not showing in Contact Detail screen

No comments:
Post a Comment