1. 程式人生 > 實用技巧 >基於android原生聯絡人app實現新建聯絡人時新增生日欄位,並且插入日曆提醒

基於android原生聯絡人app實現新建聯絡人時新增生日欄位,並且插入日曆提醒

聯絡人欄位有Name,Photo,Email,Event等型別,聯絡人app支援新建聯絡人時根據這些型別擴充套件新的欄位,新增一個Event型別的欄位就可以實現新增生日資訊,Event型別的欄位支援設定事件的名字和事件的時間,新增好後點擊就會跳到日曆中
實現見FallbackAccountType.java 裡的addDataKindEvent。
新增好後會顯示在聯絡人資訊的最下面,如果想顯示在上面可以修改QuickContactActivity.java裡的LEADING_MIMETYPES新增Event.CONTENT_ITEM_TYPE,生日資訊就會和電話顯示在一起。
點選生日資訊會跳轉到日曆中,但不會在日曆中插入提醒事件,如果想在生日時收到提醒通知,可以在儲存聯絡人時插入提醒到日曆

資料庫中,程式碼在ContactSaveService.java裡的updateBirthdayNotify,用日曆資料庫中的hasExtendedProperties欄位儲存這個提醒對應的聯絡人id,在更新聯絡人時更新對應的日曆提醒

patch如下:

diff --git a/mediatek/proprietary/packages/apps/Contacts/AndroidManifest.xml b/mediatek/proprietary/packages/apps/Contacts/AndroidManifest.xml
index 2c5b382..1499a2a 100644
--- a/mediatek/proprietary/packages/apps/Contacts/AndroidManifest.xml

+++ b/mediatek/proprietary/packages/apps/Contacts/AndroidManifest.xml
@@ -53,6 +53,7 @@
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
+ <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"/>
<!-- Following used for Contact metadata syncing -->
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
diff --git a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/ContactSaveService.java b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/ContactSaveService.java
index 9b8d5a5..032e9a0 100644
--- a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/ContactSaveService.java
+++ b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/ContactSaveService.java
@@ -44,8 +44,10 @@ import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
@@ -72,10 +74,12 @@ import com.android.contacts.model.CPOWrapper;
import com.android.contacts.model.RawContactDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.ContactDisplayUtils;
import com.android.contacts.util.ContactPhotoUtils;
+import com.android.contacts.util.DateUtils;
import com.android.contacts.util.PermissionsUtil;
import com.android.contactsbind.FeedbackHelper;

@@ -86,7 +90,9 @@ import com.mediatek.contacts.ContactSaveServiceEx;
import com.mediatek.contacts.util.Log;

import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collection;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -557,6 +563,84 @@ public class ContactSaveService extends IntentService {
}
return serviceIntent;
}
+
+ // fangao cyj add for contact birthday start
+ private void updatecalendar(final long rawContactId, String datestr, String title) {
+ long date = 0;
+ boolean everyYear = false;
+ if (datestr != null) {
+ everyYear = datestr.startsWith("--");
+ final Calendar cal = DateUtils.parseDate(datestr, false);
+ if (cal != null) {
+ final Date nextAnniversary = DateUtils.getNextAnnualDate(cal);
+ date = nextAnniversary.getTime();
+ }
+ }
+ long hasExtendedProperties = rawContactId + 100;
+ Intent i = new Intent("fangao.intent.action.BIRTHDAY_NOTIFY");
+ i.setPackage("com.android.providers.calendar");
+ i.putExtra("contactId", hasExtendedProperties);
+ i.putExtra("date", date);
+ i.putExtra("title", title);
+ i.putExtra("everyYear", everyYear);
+ sendBroadcast(i);
+ }
+
+ private void updateBirthdayNotify(RawContactDeltaList states, final long rawContactId) {
+ for (RawContactDelta delta : states) {
+ ArrayList<ValuesDelta> vds = delta.getMimeEntries(Event.CONTENT_ITEM_TYPE);
+ if (vds != null) {
+ for (ValuesDelta vd : vds) {
+ boolean isChange = false;
+ // date change
+ ContentValues before = vd.getBefore();
+ ContentValues after = vd.getAfter();
+ if ((before == null && after != null)||(after == null && before != null)) isChange = true;
+ else if(after != null && before != null) {
+ Object newValue = after.get(Event.START_DATE);
+ Object oldValue = before.get(Event.START_DATE);
+ if(newValue != null && oldValue != null && !oldValue.equals(newValue)) isChange = true;
+ }
+ // name change
+ StringBuilder atitle = new StringBuilder("");
+ StringBuilder btitle = new StringBuilder("");
+ ArrayList<ValuesDelta> namevds = delta.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ if (namevds != null && namevds.size() > 0) {
+ ContentValues ncvaf = namevds.get(0).getAfter();
+ ContentValues ncvbe = namevds.get(0).getBefore();
+ String daname = ncvaf != null?ncvaf.getAsString(StructuredName.DISPLAY_NAME):null;
+ String dbname = ncvbe != null?ncvbe.getAsString(StructuredName.DISPLAY_NAME):null;
+ if (daname != null) atitle.append(daname);
+ if (dbname != null) btitle.append(dbname);
+ String ganame = ncvaf != null?ncvaf.getAsString(StructuredName.GIVEN_NAME):null;
+ String gbname = ncvbe != null?ncvbe.getAsString(StructuredName.GIVEN_NAME):null;
+ if (ganame != null && atitle.length()==0) atitle.append(ganame);
+ if (gbname != null && btitle.length()==0) btitle.append(gbname);
+ String faname = ncvaf != null?ncvaf.getAsString(StructuredName.FAMILY_NAME):null;
+ String fbname = ncvbe != null?ncvbe.getAsString(StructuredName.FAMILY_NAME):null;
+ if (faname != null && atitle.length()==0) atitle.append(faname);
+ if (fbname != null && btitle.length()==0) btitle.append(fbname);
+
+ if (!atitle.toString().equals(btitle.toString())) isChange = true;
+
+ atitle.append("的生日");
+ }
+
+ if (isChange) {
+ String data = null;
+ if (after != null) {
+ data = after.getAsString(Event.START_DATE);
+ if (data == null) {
+ data = before == null?null:before.getAsString(Event.START_DATE);
+ }
+ }
+ updatecalendar(rawContactId, data, atitle.toString());
+ }
+ }
+ }
+ }
+ }
+ // fangao cyj add for contact birthday end

private void saveContact(Intent intent) {
RawContactDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
@@ -625,6 +709,13 @@ public class ContactSaveService extends IntentService {
if (rawContactId == -1) {
throw new IllegalStateException("Could not determine RawContact ID after save");
}
+ // fangao start
+ try {
+ updateBirthdayNotify(state, rawContactId);
+ } catch(Exception e) {
+ Log.e(TAG, "updateBirthdayNotify error:"+e);
+ }
+ // fangao end
// We don't have to check to see if the value is still -1. If we reach here,
// the previous loop iteration didn't succeed, so any ID that we obtained is bogus.
insertedRawContactId = getInsertedRawContactId(diffWrapper, results);
diff --git a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/model/account/FallbackAccountType.java b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/model/account/FallbackAccountType.java
index dd2f15c..bbc4105 100644
--- a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/model/account/FallbackAccountType.java
+++ b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/model/account/FallbackAccountType.java
@@ -22,16 +22,24 @@
package com.android.contacts.model.account;

import android.accounts.AuthenticatorDescription;
+import android.content.ContentValues;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.CommonDataKinds.Event;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;

import com.android.contacts.R;
+import com.android.contacts.model.account.AccountType.DefinitionException;
+import com.android.contacts.model.account.AccountType.EditField;
+import com.android.contacts.model.account.BaseAccountType.EventActionInflater;
+import com.android.contacts.model.account.BaseAccountType.SimpleInflater;
+import com.android.contacts.model.account.BaseAccountType.Weight;
import com.android.contacts.model.dataitem.DataKind;
+import com.android.contacts.util.CommonDateUtils;
import com.android.contactsbind.FeedbackHelper;
-
+import com.google.common.collect.Lists;
import com.mediatek.contacts.util.Log;

public class FallbackAccountType extends BaseAccountType {
@@ -62,12 +70,40 @@ public class FallbackAccountType extends BaseAccountType {
addDataKindWebsite(context);
addDataKindSipAddress(context);
addDataKindGroupMembership(context);
+ addDataKindEvent(context);// fangao cyj add for contacts birthday

mIsInitialized = true;
} catch (DefinitionException e) {
FeedbackHelper.sendFeedback(context, TAG, "Failed to build fallback account type", e);
}
}
+
+ // fangao cyj add for contacts birthday start
+ private DataKind addDataKindEvent(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
+ R.string.eventLabelsGroup, Weight.PHONE, true));
+ kind.actionHeader = new EventActionInflater();
+ kind.actionBody = new SimpleInflater(Event.START_DATE);
+
+ kind.typeColumn = Event.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_FORMAT;
+ kind.dateFormatWithYear = CommonDateUtils.FULL_DATE_FORMAT;
+ kind.typeList.add(buildEventType(Event.TYPE_BIRTHDAY, true).setSpecificMax(1));
+// kind.typeList.add(buildEventType(Event.TYPE_ANNIVERSARY, false));
+// kind.typeList.add(buildEventType(Event.TYPE_OTHER, false));
+// kind.typeList.add(buildEventType(Event.TYPE_CUSTOM, false).setSecondary(true)
+// .setCustomColumn(Event.LABEL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
+
+ return kind;
+ }
+ // fangao cyj add for contacts birthday end

@Override
public Drawable getDisplayIcon(Context context) {
diff --git a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/quickcontact/QuickContactActivity.java b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 6c03f9f..1b2bcab 100644
--- a/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/mediatek/proprietary/packages/apps/Contacts/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -355,7 +355,7 @@ public class QuickContactActivity extends ContactsActivity {
*/
private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE,
- StructuredPostal.CONTENT_ITEM_TYPE);
+ StructuredPostal.CONTENT_ITEM_TYPE,Event.CONTENT_ITEM_TYPE); // fangao cyj add Event show birthday on the top

private static final List<String> SORTED_ABOUT_CARD_MIMETYPES = Lists.newArrayList(
Nickname.CONTENT_ITEM_TYPE,
@@ -363,7 +363,6 @@ public class QuickContactActivity extends ContactsActivity {
// No mimetype for phonetic name exists.
Website.CONTENT_ITEM_TYPE,
Organization.CONTENT_ITEM_TYPE,
- Event.CONTENT_ITEM_TYPE,
Relation.CONTENT_ITEM_TYPE,
Im.CONTENT_ITEM_TYPE,
GroupMembership.CONTENT_ITEM_TYPE,
@@ -1794,8 +1793,17 @@ public class QuickContactActivity extends ContactsActivity {
event.getLabel()).toString();
}
text = DateUtils.formatDate(context, dataString);
+ // fangao cyj add for contact birthday start
+ header = text;
+ text = subHeader;
+ subHeader = null;
+ // fangao cyj add for contact birthday end
entryContextMenuInfo = new EntryContextMenuInfo(text, header,
dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
+ // fangao cyj add for contact birthday start
+ iconResourceId = R.drawable.quantum_ic_event_vd_theme_24;
+ icon = res.getDrawable(iconResourceId);
+ // fangao cyj add for contact birthday end
} else if (dataItem instanceof RelationDataItem) {
final RelationDataItem relation = (RelationDataItem) dataItem;
final String dataString = relation.buildDataStringForDisplay(context, kind);
diff --git a/mediatek/proprietary/packages/providers/CalendarProvider/AndroidManifest.xml b/mediatek/proprietary/packages/providers/CalendarProvider/AndroidManifest.xml
index 907587a..3d683d9 100755
--- a/mediatek/proprietary/packages/providers/CalendarProvider/AndroidManifest.xml
+++ b/mediatek/proprietary/packages/providers/CalendarProvider/AndroidManifest.xml
@@ -118,6 +118,12 @@
<action android:name="com.mediatek.intent.action.SETTINGS_PACKAGE_DATA_CLEARED" />
</intent-filter>
</receiver>
+ <!-- fangao cyj add update calendar when add contact birthday -->
+ <receiver android:name="BirthdayNotifyReceiver">
+ <intent-filter>
+ <action android:name="fangao.intent.action.BIRTHDAY_NOTIFY"/>
+ </intent-filter>
+ </receiver>

</application>
</manifest>
diff --git a/mediatek/proprietary/packages/providers/CalendarProvider/src/com/android/providers/calendar/BirthdayNotifyReceiver.java b/mediatek/proprietary/packages/providers/CalendarProvider/src/com/android/providers/calendar/BirthdayNotifyReceiver.java
new file mode 100755
index 0000000..6dd7e10
--- /dev/null
+++ b/mediatek/proprietary/packages/providers/CalendarProvider/src/com/android/providers/calendar/BirthdayNotifyReceiver.java
@@ -0,0 +1,113 @@
+
+
+package com.android.providers.calendar;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.PowerManager;
+import android.provider.CalendarContract;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * fangao cyj add for contact birthday
+ */
+public class BirthdayNotifyReceiver extends BroadcastReceiver {
+ private static final String TAG = "BirthdayNotifyReceiver";
+ static final String SCHEDULE = "com.android.providers.calendar.SCHEDULE_ALARM";
+
+ private final ExecutorService executor = Executors.newCachedThreadPool();
+ private PowerManager.WakeLock mWakeLock;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ long contactId = intent.getLongExtra("contactId", -1);
+ long date = intent.getLongExtra("date", -1);
+ String title = intent.getStringExtra("title");
+ boolean everyYear = intent.getBooleanExtra("everyYear", false);
+ if (contactId != -1 && date != -1 && title != null) {
+ updatecalendar(context, contactId, date, title, everyYear);
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "BirthdayNotifyReceiver updatecalendar error:"+e);
+ }
+
+ }
+
+ private void updatecalendar(Context context, final long hasExtendedProperties, long date, String title, boolean everyYear) {
+ // delete first
+ Cursor cur = null;
+ ContentResolver cr = context.getContentResolver();
+ Uri uri = CalendarContract.Events.CONTENT_URI;
+ String[] EVENT_PROJECTION = new String[]{
+ CalendarContract.Events._ID
+ };
+ String selection = "(" + CalendarContract.Events.HAS_EXTENDED_PROPERTIES + " = ?)";
+ String[] selectionArgs = new String[]{String.valueOf(hasExtendedProperties)};
+ cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
+ ArrayList<Long> events = new ArrayList<>();
+ while (cur.moveToNext()) {
+ events.add(cur.getLong(0));
+ }
+ for(Long eventId : events) {
+ selection = "(" + CalendarContract.Events._ID + " = ?)";
+ selectionArgs = new String[]{String.valueOf(eventId)};
+ cr.delete(uri, selection, selectionArgs);
+
+ selection = "(" + CalendarContract.Reminders.EVENT_ID + " = ?)";
+ selectionArgs = new String[]{String.valueOf(eventId)};
+ cr.delete(CalendarContract.Reminders.CONTENT_URI, selection, selectionArgs);
+ }
+ // insert
+ if (date != 0) {
+ long daymillis = 24*3600*1000;
+ ContentValues values = new ContentValues();
+ values.put(CalendarContract.Events.HAS_EXTENDED_PROPERTIES, hasExtendedProperties); // Contactid
+ values.put(CalendarContract.Events.CALENDAR_ID, 1);
+ values.put(CalendarContract.Events.DTSTART, date);
+ values.put(CalendarContract.Events.TITLE, title);
+ //values.put(CalendarContract.Events.DESCRIPTION, calender.description);
+ //values.put(CalendarContract.Events.EVENT_LOCATION, calender.eventLocation);
+ values.put(CalendarContract.Events.EVENT_TIMEZONE, "UTC");
+ values.put(CalendarContract.Events.ACCESS_LEVEL, 0);
+ values.put(CalendarContract.Events.ALL_DAY, 1);
+ values.put(CalendarContract.Events.ORGANIZER, "PC Sync");
+ values.put(CalendarContract.Events.STATUS, 1);
+
+ if (everyYear) {
+ values.put(CalendarContract.Events.DURATION, "P1D"); // every year
+ values.put(CalendarContract.Events.RRULE, "FREQ=YEARLY;WKST=SU"); // every year
+ } else {
+ values.put(CalendarContract.Events.DTEND, date+daymillis);
+ values.put(CalendarContract.Events.LAST_DATE, date+daymillis);
+ }
+
+ // add Reminder
+ values.put(CalendarContract.Events.HAS_ALARM, 1);
+
+ Uri eventUri = cr.insert(uri, values);
+
+ // get the event ID that is the last element in the Uri
+ long eventID = Long.parseLong(eventUri.getLastPathSegment());
+
+ // add Reminder
+ ContentValues reminderValues = new ContentValues();
+ reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventID);
+ reminderValues.put(CalendarContract.Reminders.MINUTES, 12*60);// 提前XXXX有提醒
+ reminderValues.put(CalendarContract.Reminders.METHOD, 1);// 提醒方式
+
+ cr.insert(CalendarContract.Reminders.CONTENT_URI, reminderValues);
+ }
+
+ }
+
+}

效果如下: