Loading core/java/android/pim/vcard/VCardComposer.java +202 −38 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import android.provider.ContactsContract.CommonDataKinds.Website; import android.provider.CallLog.Calls; import android.provider.CallLog; import android.text.format.DateUtils; import android.text.format.Time; import android.text.TextUtils; import android.util.CharsetUtils; import android.util.Log; Loading Loading @@ -213,6 +217,9 @@ public class VCardComposer { private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME"; // TODO: add properties like X-LATITUDE // Property for call log entry private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME"; // Properties for DoCoMo vCard. private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS"; private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION"; Loading @@ -227,6 +234,7 @@ public class VCardComposer { private static final String VCARD_DATA_SEPARATOR = ":"; private static final String VCARD_ITEM_SEPARATOR = ";"; private static final String VCARD_WS = " "; private static final String VCARD_ATTR_EQUAL = "="; // Type strings are now in VCardConstants.java. Loading @@ -238,20 +246,20 @@ public class VCardComposer { private static final String SHIFT_JIS = "SHIFT_JIS"; private final Context mContext; private final int mVCardType; private final boolean mCareHandlerErrors; private final ContentResolver mContentResolver; private int mVCardType; private boolean mCareHandlerErrors; private ContentResolver mContentResolver; // Convenient member variables about the restriction of the vCard format. // Used for not calling the same methods returning same results. private final boolean mIsV30; private final boolean mIsJapaneseMobilePhone; private final boolean mOnlyOneNoteFieldIsAvailable; private final boolean mIsDoCoMo; private final boolean mUsesQuotedPrintable; private final boolean mUsesAndroidProperty; private final boolean mUsesDefactProperty; private final boolean mUsesShiftJis; private boolean mIsV30; private boolean mIsJapaneseMobilePhone; private boolean mOnlyOneNoteFieldIsAvailable; private boolean mIsDoCoMo; private boolean mUsesQuotedPrintable; private boolean mUsesAndroidProperty; private boolean mUsesDefactProperty; private boolean mUsesShiftJis; private Cursor mCursor; private int mIdColumn; Loading @@ -276,6 +284,25 @@ public class VCardComposer { // Google talk is a special case. } private boolean mIsCallLogComposer = false; private static final String[] CONTACTS_PROJECTION = new String[] { Contacts._ID, }; /** The projection to use when querying the call log table */ private static final String[] CALL_LOG_PROJECTION = new String[] { Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_LABEL }; private static final int NUMBER_COLUMN_INDEX = 0; private static final int DATE_COLUMN_INDEX = 1; private static final int CALL_TYPE_COLUMN_INDEX = 2; private static final int CALLER_NAME_COLUMN_INDEX = 3; private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4; private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5; private static final String FLAG_TIMEZONE_UTC = "Z"; public VCardComposer(Context context) { this(context, VCardConfig.VCARD_TYPE_DEFAULT, true); Loading @@ -287,10 +314,15 @@ public class VCardComposer { careHandlerErrors); } public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) { /** * Construct for supporting call log entry vCard composing */ public VCardComposer(Context context, int vcardType, boolean careHandlerErrors, boolean isCallLogComposer) { mContext = context; mVCardType = vcardType; mCareHandlerErrors = careHandlerErrors; mIsCallLogComposer = isCallLogComposer; mContentResolver = context.getContentResolver(); mIsV30 = VCardConfig.isV30(vcardType); Loading Loading @@ -320,6 +352,38 @@ public class VCardComposer { } } public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) { this(context, vcardType, careHandlerErrors, false); } /** * This static function is to compose vCard for phone own number */ public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName, String phoneNumber, boolean vcardVer21) { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); if (!vcardVer21) { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30); } else { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21); } boolean needCharset = false; if (!(VCardUtils.containsOnlyAscii(phoneName))) { needCharset = true; } appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, phoneName, needCharset, false); appendVCardLine(builder, VCARD_PROPERTY_NAME, phoneName, needCharset, false); String label = Integer.toString(phonetype); appendVCardTelephoneLine(builder, phonetype, label, phoneNumber); appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD); return builder.toString(); } /** * Must call before {{@link #init()}. */ Loading Loading @@ -357,11 +421,15 @@ public class VCardComposer { } } final String[] projection = new String[] {Contacts._ID,}; if (mIsCallLogComposer) { mCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, CALL_LOG_PROJECTION, selection, selectionArgs, null); } else { // TODO: thorow an appropriate exception! mCursor = mContentResolver.query(RawContacts.CONTENT_URI, projection, mCursor = mContentResolver.query(RawContacts.CONTENT_URI, CONTACTS_PROJECTION, selection, selectionArgs, null); } if (mCursor == null || !mCursor.moveToFirst()) { if (mCursor != null) { try { Loading @@ -376,7 +444,11 @@ public class VCardComposer { return false; } if (mIsCallLogComposer) { mIdColumn = -1; } else { mIdColumn = mCursor.getColumnIndex(Contacts._ID); } return true; } Loading @@ -390,7 +462,16 @@ public class VCardComposer { String name = null; String vcard; try { if (mIsCallLogComposer) { vcard = createOneCallLogEntryInternal(); } else { if (mIdColumn >= 0) { vcard = createOneEntryInternal(mCursor.getString(mIdColumn)); } else { Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn); return true; } } } catch (OutOfMemoryError error) { // Maybe some data (e.g. photo) is too big to have in memory. But it // should be rare. Loading Loading @@ -422,6 +503,89 @@ public class VCardComposer { return true; } /** * Format according to RFC 2445 DATETIME type. * The format is: ("%Y%m%dT%H%M%S"). */ private final String formatDate(final long millSecs) { Time startDate = new Time(); startDate.set(millSecs); String date = startDate.format2445(); return date + FLAG_TIMEZONE_UTC; } /** * Create call history time stamp field. * * @param type call type */ private String createCallHistoryTimeStampField(int type) { // Extension for call history as defined in // in the Specification for Ic Mobile Communcation - ver 1.1, // Oct 2000. This is used to send the details of the call // history - missed, incoming, outgoing along with date and time // to the requesting device (For example, transferring phone book // when connected over bluetooth) // X-IRMC-CALL-DATETIME;MISSED:20050320T100000 final StringBuilder builder = new StringBuilder(); builder.append(VCARD_PROPERTY_X_TIMESTAMP); builder.append(VCARD_ATTR_SEPARATOR); if (mIsV30) { builder.append(Constants.ATTR_TYPE).append(VCARD_ATTR_EQUAL); } if (type == Calls.INCOMING_TYPE) { builder.append("INCOMING"); } else if (type == Calls.OUTGOING_TYPE) { builder.append("OUTGOING"); } else if (type == Calls.MISSED_TYPE) { builder.append("MISSED"); } else { Log.w(LOG_TAG, "Call log type not correct."); return null; } return builder.toString(); } private String createOneCallLogEntryInternal() { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); if (mIsV30) { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30); } else { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21); } String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX); if (TextUtils.isEmpty(name)) { name = mCursor.getString(NUMBER_COLUMN_INDEX); } boolean needCharset = !(VCardUtils.containsOnlyAscii(name)); appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, name, needCharset, false); appendVCardLine(builder, VCARD_PROPERTY_NAME, name, needCharset, false); String number = mCursor.getString(NUMBER_COLUMN_INDEX); int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); if (TextUtils.isEmpty(label)) { label = Integer.toString(type); } appendVCardTelephoneLine(builder, type, label, number); long date = mCursor.getLong(DATE_COLUMN_INDEX); String dateClause = formatDate(date); int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX); String timestampFeldString = createCallHistoryTimeStampField(callLogType); if (timestampFeldString != null) { appendVCardLine(builder, timestampFeldString, dateClause); } appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD); return builder.toString(); } private String createOneEntryInternal(final String contactId) { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); Loading Loading
core/java/android/pim/vcard/VCardComposer.java +202 −38 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import android.provider.ContactsContract.CommonDataKinds.Website; import android.provider.CallLog.Calls; import android.provider.CallLog; import android.text.format.DateUtils; import android.text.format.Time; import android.text.TextUtils; import android.util.CharsetUtils; import android.util.Log; Loading Loading @@ -213,6 +217,9 @@ public class VCardComposer { private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME"; // TODO: add properties like X-LATITUDE // Property for call log entry private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME"; // Properties for DoCoMo vCard. private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS"; private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION"; Loading @@ -227,6 +234,7 @@ public class VCardComposer { private static final String VCARD_DATA_SEPARATOR = ":"; private static final String VCARD_ITEM_SEPARATOR = ";"; private static final String VCARD_WS = " "; private static final String VCARD_ATTR_EQUAL = "="; // Type strings are now in VCardConstants.java. Loading @@ -238,20 +246,20 @@ public class VCardComposer { private static final String SHIFT_JIS = "SHIFT_JIS"; private final Context mContext; private final int mVCardType; private final boolean mCareHandlerErrors; private final ContentResolver mContentResolver; private int mVCardType; private boolean mCareHandlerErrors; private ContentResolver mContentResolver; // Convenient member variables about the restriction of the vCard format. // Used for not calling the same methods returning same results. private final boolean mIsV30; private final boolean mIsJapaneseMobilePhone; private final boolean mOnlyOneNoteFieldIsAvailable; private final boolean mIsDoCoMo; private final boolean mUsesQuotedPrintable; private final boolean mUsesAndroidProperty; private final boolean mUsesDefactProperty; private final boolean mUsesShiftJis; private boolean mIsV30; private boolean mIsJapaneseMobilePhone; private boolean mOnlyOneNoteFieldIsAvailable; private boolean mIsDoCoMo; private boolean mUsesQuotedPrintable; private boolean mUsesAndroidProperty; private boolean mUsesDefactProperty; private boolean mUsesShiftJis; private Cursor mCursor; private int mIdColumn; Loading @@ -276,6 +284,25 @@ public class VCardComposer { // Google talk is a special case. } private boolean mIsCallLogComposer = false; private static final String[] CONTACTS_PROJECTION = new String[] { Contacts._ID, }; /** The projection to use when querying the call log table */ private static final String[] CALL_LOG_PROJECTION = new String[] { Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_LABEL }; private static final int NUMBER_COLUMN_INDEX = 0; private static final int DATE_COLUMN_INDEX = 1; private static final int CALL_TYPE_COLUMN_INDEX = 2; private static final int CALLER_NAME_COLUMN_INDEX = 3; private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4; private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5; private static final String FLAG_TIMEZONE_UTC = "Z"; public VCardComposer(Context context) { this(context, VCardConfig.VCARD_TYPE_DEFAULT, true); Loading @@ -287,10 +314,15 @@ public class VCardComposer { careHandlerErrors); } public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) { /** * Construct for supporting call log entry vCard composing */ public VCardComposer(Context context, int vcardType, boolean careHandlerErrors, boolean isCallLogComposer) { mContext = context; mVCardType = vcardType; mCareHandlerErrors = careHandlerErrors; mIsCallLogComposer = isCallLogComposer; mContentResolver = context.getContentResolver(); mIsV30 = VCardConfig.isV30(vcardType); Loading Loading @@ -320,6 +352,38 @@ public class VCardComposer { } } public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) { this(context, vcardType, careHandlerErrors, false); } /** * This static function is to compose vCard for phone own number */ public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName, String phoneNumber, boolean vcardVer21) { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); if (!vcardVer21) { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30); } else { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21); } boolean needCharset = false; if (!(VCardUtils.containsOnlyAscii(phoneName))) { needCharset = true; } appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, phoneName, needCharset, false); appendVCardLine(builder, VCARD_PROPERTY_NAME, phoneName, needCharset, false); String label = Integer.toString(phonetype); appendVCardTelephoneLine(builder, phonetype, label, phoneNumber); appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD); return builder.toString(); } /** * Must call before {{@link #init()}. */ Loading Loading @@ -357,11 +421,15 @@ public class VCardComposer { } } final String[] projection = new String[] {Contacts._ID,}; if (mIsCallLogComposer) { mCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, CALL_LOG_PROJECTION, selection, selectionArgs, null); } else { // TODO: thorow an appropriate exception! mCursor = mContentResolver.query(RawContacts.CONTENT_URI, projection, mCursor = mContentResolver.query(RawContacts.CONTENT_URI, CONTACTS_PROJECTION, selection, selectionArgs, null); } if (mCursor == null || !mCursor.moveToFirst()) { if (mCursor != null) { try { Loading @@ -376,7 +444,11 @@ public class VCardComposer { return false; } if (mIsCallLogComposer) { mIdColumn = -1; } else { mIdColumn = mCursor.getColumnIndex(Contacts._ID); } return true; } Loading @@ -390,7 +462,16 @@ public class VCardComposer { String name = null; String vcard; try { if (mIsCallLogComposer) { vcard = createOneCallLogEntryInternal(); } else { if (mIdColumn >= 0) { vcard = createOneEntryInternal(mCursor.getString(mIdColumn)); } else { Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn); return true; } } } catch (OutOfMemoryError error) { // Maybe some data (e.g. photo) is too big to have in memory. But it // should be rare. Loading Loading @@ -422,6 +503,89 @@ public class VCardComposer { return true; } /** * Format according to RFC 2445 DATETIME type. * The format is: ("%Y%m%dT%H%M%S"). */ private final String formatDate(final long millSecs) { Time startDate = new Time(); startDate.set(millSecs); String date = startDate.format2445(); return date + FLAG_TIMEZONE_UTC; } /** * Create call history time stamp field. * * @param type call type */ private String createCallHistoryTimeStampField(int type) { // Extension for call history as defined in // in the Specification for Ic Mobile Communcation - ver 1.1, // Oct 2000. This is used to send the details of the call // history - missed, incoming, outgoing along with date and time // to the requesting device (For example, transferring phone book // when connected over bluetooth) // X-IRMC-CALL-DATETIME;MISSED:20050320T100000 final StringBuilder builder = new StringBuilder(); builder.append(VCARD_PROPERTY_X_TIMESTAMP); builder.append(VCARD_ATTR_SEPARATOR); if (mIsV30) { builder.append(Constants.ATTR_TYPE).append(VCARD_ATTR_EQUAL); } if (type == Calls.INCOMING_TYPE) { builder.append("INCOMING"); } else if (type == Calls.OUTGOING_TYPE) { builder.append("OUTGOING"); } else if (type == Calls.MISSED_TYPE) { builder.append("MISSED"); } else { Log.w(LOG_TAG, "Call log type not correct."); return null; } return builder.toString(); } private String createOneCallLogEntryInternal() { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); if (mIsV30) { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30); } else { appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21); } String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX); if (TextUtils.isEmpty(name)) { name = mCursor.getString(NUMBER_COLUMN_INDEX); } boolean needCharset = !(VCardUtils.containsOnlyAscii(name)); appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, name, needCharset, false); appendVCardLine(builder, VCARD_PROPERTY_NAME, name, needCharset, false); String number = mCursor.getString(NUMBER_COLUMN_INDEX); int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); if (TextUtils.isEmpty(label)) { label = Integer.toString(type); } appendVCardTelephoneLine(builder, type, label, number); long date = mCursor.getLong(DATE_COLUMN_INDEX); String dateClause = formatDate(date); int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX); String timestampFeldString = createCallHistoryTimeStampField(callLogType); if (timestampFeldString != null) { appendVCardLine(builder, timestampFeldString, dateClause); } appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD); return builder.toString(); } private String createOneEntryInternal(final String contactId) { final StringBuilder builder = new StringBuilder(); appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD); Loading