AndroidManifest.xml添加声明
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
先请求权限
/**
* 请求通话记录权限
*/
@Composable
internal fun CheckPermissions(context: Context) {
val callLogPermissions = arrayOf(
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
)
val permissionsError = stringResource(id = R.string.permissions_error)
val rememberLauncherForActivityResult =
rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestMultiplePermissions()) { result ->
if (!(result[Manifest.permission.WRITE_CALL_LOG] == true || result[Manifest.permission.READ_CALL_LOG] == true || result[Manifest.permission.CALL_PHONE] == true)) {
Toast.makeText(
context, permissionsError, Toast.LENGTH_LONG
).show()
}
}
SideEffect {
rememberLauncherForActivityResult.launch(callLogPermissions)
}
}
获取通话记录
/**
* 通话记录工具类
*/
object CallLogUtil {
private val carrierMap = mapOf(
"China Mobile" to "移动",
"China Unicom" to "联通",
"China Telecom" to "电信",
)
private val phoneNumberUtil: PhoneNumberUtil = PhoneNumberUtil.getInstance()
private val carrierMapper: PhoneNumberToCarrierMapper = PhoneNumberToCarrierMapper.getInstance()
private val geocoder: PhoneNumberOfflineGeocoder = PhoneNumberOfflineGeocoder.getInstance()
private const val CHINA_LANGUAGE: String = "CN"
/**
* 根据号码查询通话记录
*/
fun getCallLogByNumber(contentResolver: ContentResolver, number: String): Cursor? {
val projection = arrayOf(
CallLog.Calls.CACHED_NAME,
CallLog.Calls.NUMBER,
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
CallLog.Calls.TYPE
)
val selection = "${CallLog.Calls.NUMBER} = ?"
val selectionArgs = arrayOf(number)
return contentResolver.query(
CallLog.Calls.CONTENT_URI,
projection,
selection,
selectionArgs,
CallLog.Calls.DEFAULT_SORT_ORDER
)
}
/**
* 获取查询通话记录
*/
fun getCallLog (contentResolver: ContentResolver): LinkedHashMap<String, MutableList<CallLogEntity>> {
val linkedHashMap = linkedMapOf<String, MutableList<CallLogEntity>>()
val columns = arrayOf(
CallLog.Calls.CACHED_NAME, // 通话记录的联系人
CallLog.Calls.NUMBER, // 通话记录的电话号码
CallLog.Calls.DATE, // 通话记录的日期
CallLog.Calls.DURATION, // 通话时长
CallLog.Calls.TYPE // 通话类型
)
val cursor = contentResolver.query(
CallLog.Calls.CONTENT_URI,
columns,
null,
null,
// 按照时间逆序排列,最近打的最先显示
CallLog.Calls.DEFAULT_SORT_ORDER
)
val startTime = System.currentTimeMillis()
var count = 0
if (cursor != null) {
val nameIndex = cursor.getColumnIndex(CallLog.Calls.CACHED_NAME)
val numberIndex = cursor.getColumnIndex(CallLog.Calls.NUMBER)
val dateIndex = cursor.getColumnIndex(CallLog.Calls.DATE)
val durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION)
val typeIndex = cursor.getColumnIndex(CallLog.Calls.TYPE)
while (cursor.moveToNext() && count < 20) {
// 姓名
val name = cursor.getString(nameIndex)
// 号码
val number = cursor.getString(numberIndex)
// 获取通话日期
val dateLong = cursor.getLong(dateIndex)
// 通话日期
val date: String =
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(dateLong))
// 通话时间
val time: String =
SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date(dateLong))
// 获取通话时长,单位:秒
val duration = cursor.getInt(durationIndex)
// 获取通话类型:1.呼入2.呼出3.未接
val type = cursor.getInt(typeIndex)
count++
val callLogEntity = CallLogEntity(
number,
name, dateLong, date, time, getCarrier(number), getGen(number), duration, type,
)
// 检查手机号是否已在Map中
if (linkedHashMap.containsKey(number)) {
// 如果存在,添加到现有的列表中
linkedHashMap[number]?.add(callLogEntity)
} else {
// 如果不存在,新建列表并添加到Map中
linkedHashMap[number] = mutableListOf(callLogEntity)
}
}
}
val endTime = System.currentTimeMillis()
cursor?.close()
Log.i("TAG", "执行时间: ${endTime - startTime} ms")
return linkedHashMap
}
// 初始化通话时长
fun formatDuration(time: Long): String {
val s = time % 60
val m = time / 60
val h = time / 60 / 60
val sb = StringBuilder()
if (h > 0) {
sb.append(h).append("小时")
}
if (m > 0) {
sb.append(m).append("分")
}
sb.append(s).append("秒")
return sb.toString()
}
private fun getCarrier(phoneNumber: String): String {
val referencePhoneNumber = phoneNumberUtil.parse(phoneNumber, CHINA_LANGUAGE)
val carrierEn = carrierMapper.getNameForNumber(referencePhoneNumber, Locale.ENGLISH)
return carrierMap[carrierEn] ?: ""
}
private fun getGen(phoneNumber: String): String {
val referencePhoneNumber = phoneNumberUtil.parse(phoneNumber, CHINA_LANGUAGE)
val descriptionForNumber =
geocoder.getDescriptionForNumber(referencePhoneNumber, Locale.CHINA)
return descriptionForNumber.ifBlank { "未知归属地" }
}
}
data class CallLogEntity(
// 手机号
val phoneNumber: String,
// 名称
val name: String?,
// 时间戳
val timestamp: Long,
// 日期
val date: String,
// 时间
val time: String,
// 归属地
val belongPlace: String,
// 运营商名称
val netName: String,
// 通话时长
val duration: Int,
// 类型
val type: Int
)
这里需要导包,来获取运营商以及归属地信息,最好去找最新的库,要不然最近几年出的号码会显示为空。也能使用百度提供的接口获取信息
//谷歌电话号码归属地库
implementation 'com.googlecode.libphonenumber:libphonenumber:8.10.3'
implementation 'com.googlecode.libphonenumber:carrier:1.99'
implementation 'com.googlecode.libphonenumber:geocoder:2.99'
implementation 'com.googlecode.libphonenumber:prefixmapper:2.109'
获取联系人信息
/**
* 联系人工具类
*/
object ContactPersonUtil {
/**
* 获取手机联系人详细信息列表
*/
fun getContactsDetails(context: Context): MutableList<ContactPersonEntity> {
val startTime = System.currentTimeMillis()
val contactDetailsList = mutableListOf<ContactPersonEntity>()
val contentResolver = context.contentResolver
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
arrayOf(ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME),
null,
null,
ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"
)
if (cursor != null && cursor.count > 0) {
while (cursor.moveToNext()) {
val contactPersonEntity = ContactPersonEntity()
val columnIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID)
contactPersonEntity.contactId = cursor.getString(columnIndex)
val displayNameColumn =
cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
contactPersonEntity.disPlayName = cursor.getString(displayNameColumn)
// 获取手机号
getPhone(contentResolver, contactPersonEntity)
// 获取邮箱
getEmail(contentResolver, contactPersonEntity)
// 获取IM
getIM(contentResolver, context, contactPersonEntity)
// 获取地址
getAddress(contentResolver, contactPersonEntity)
// 获取组织
getOrganizations(contentResolver, contactPersonEntity)
// 获取备注
getNote(contentResolver, contactPersonEntity)
// 获取昵称
getNickName(contentResolver, contactPersonEntity)
// 获取事件
getBirth(contentResolver, contactPersonEntity)
// 获取网址
getWebsites(contentResolver, contactPersonEntity)
// 获取头像
getAvatar(contentResolver, contactPersonEntity)
contactDetailsList.add(contactPersonEntity)
}
cursor.close()
}
// 记录结束时间并计算耗时
val endTime = System.currentTimeMillis()
val duration = endTime - startTime
Log.d("TAG", "获取联系人详情耗时:$duration 毫秒")
return contactDetailsList
}
private fun getAvatar(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val contactUri = Uri.withAppendedPath(
ContactsContract.Contacts.CONTENT_URI, contactPersonEntity.contactId
)
val iconIs = ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri)
if (iconIs != null) {
// 解码输入流为 Bitmap
val bitmap = BitmapFactory.decodeStream(iconIs)
contactPersonEntity.avatar = bitmap
iconIs.close()
} else {
// 处理头像不存在的情况,比如设置默认头像
contactPersonEntity.avatar = null
}
}
private fun getWebsites(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val websiteList = mutableListOf<WebsiteEntity>()
val websites = contentResolver.query(
Data.CONTENT_URI,
arrayOf(
Data.DATA1, // 存储网址的列
ContactsContract.CommonDataKinds.Website.TYPE,
ContactsContract.CommonDataKinds.Website.LABEL
),
"${Data.CONTACT_ID} = ? AND ${Data.MIMETYPE} = ?",
arrayOf(
contactPersonEntity.contactId.toString(),
ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE
),
null
)
if (websites != null && websites.moveToFirst()) {
do {
val websiteEntity = WebsiteEntity()
// 获取网址URL
val urlColumnIndex = websites.getColumnIndex(Data.DATA1)
websiteEntity.url = websites.getString(urlColumnIndex)
// 获取类型
val typeIndex =
websites.getColumnIndex(ContactsContract.CommonDataKinds.Website.TYPE)
val type = websites.getInt(typeIndex)
// 获取自定义标签
val labelIndex =
websites.getColumnIndex(ContactsContract.CommonDataKinds.Website.LABEL)
val label = websites.getString(labelIndex)
// 根据类型设置标签
websiteEntity.type = when (type) {
ContactsContract.CommonDataKinds.Website.TYPE_HOMEPAGE -> "个人主页"
ContactsContract.CommonDataKinds.Website.TYPE_WORK -> "工作"
ContactsContract.CommonDataKinds.Website.TYPE_BLOG -> "博客"
ContactsContract.CommonDataKinds.Website.TYPE_PROFILE -> "个人资料"
ContactsContract.CommonDataKinds.Website.TYPE_FTP -> "FTP"
ContactsContract.CommonDataKinds.Website.TYPE_CUSTOM -> label ?: "自定义"
else -> "网址"
}
websiteList.add(websiteEntity)
} while (websites.moveToNext())
}
contactPersonEntity.websiteEntityList = websiteList
websites?.close()
}
private fun getBirth(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val list = mutableListOf<EventEntity>()
// 查询条件,包括 contactId 的匹配
val selection = contentResolver.query(
Data.CONTENT_URI,
arrayOf(
Data.RAW_CONTACT_ID,
Event.TYPE,
Event.START_DATE,
Data.DATA3
), // DATA3 用于存储自定义事件名称
"${Event.MIMETYPE} = ? AND ${Data.RAW_CONTACT_ID} = ?",
arrayOf(Event.CONTENT_ITEM_TYPE, contactPersonEntity.contactId.toString()),
null
)
if (selection != null && selection.moveToFirst()) {
do {
val eventEntity = EventEntity()
// 获取列索引
val dateIndex = selection.getColumnIndex(Event.START_DATE)
val eventTypeIndex = selection.getColumnIndex(Event.TYPE)
val customLabelIndex = selection.getColumnIndex(Data.DATA3) // 获取自定义标签的索引
// 获取事件日期和类型
val date = selection.getString(dateIndex) ?: "无日期" // 如果没有日期则返回"无日期"
val eventType = selection.getInt(eventTypeIndex)
val customLabel = selection.getString(customLabelIndex) // 获取自定义标签
// 根据类型和自定义名称确定事件描述
val eventDescription = when (eventType) {
Event.TYPE_BIRTHDAY -> "生日"
Event.TYPE_ANNIVERSARY -> "纪念日"
else -> customLabel ?: "其他" // 如果自定义标签为空,则返回"其他"
}
eventEntity.event = eventDescription
eventEntity.date = date
list.add(eventEntity)
} while (selection.moveToNext())
}
contactPersonEntity.eventEntityList = list
selection?.close()
}
private fun getNickName(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val nickNameCursor = contentResolver.query(
Data.CONTENT_URI,
arrayOf(Data._ID, Nickname.NAME),
"${Data.CONTACT_ID} =? AND ${Data.MIMETYPE} = '${Nickname.CONTENT_ITEM_TYPE}'",
arrayOf(contactPersonEntity.contactId),
null
)
if (nickNameCursor != null && nickNameCursor.moveToFirst()) {
val columnIndex = nickNameCursor.getColumnIndex(Nickname.NAME)
contactPersonEntity.nickName = nickNameCursor.getString(columnIndex)
}
nickNameCursor?.close()
}
private fun getNote(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val notes = contentResolver.query(
Data.CONTENT_URI,
arrayOf(Data._ID, Note.NOTE),
"${Data.CONTACT_ID} =? AND ${Data.MIMETYPE} = '${Note.CONTENT_ITEM_TYPE}'",
arrayOf(contactPersonEntity.contactId),
null
)
if (notes != null && notes.moveToFirst()) {
val columnIndex = notes.getColumnIndex(Note.NOTE)
contactPersonEntity.noteinfo = notes.getString(columnIndex)
}
notes?.close()
}
private fun getOrganizations(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val organizationsList = mutableListOf<OrganizationsEntity>()
val organizations = contentResolver.query(
Data.CONTENT_URI,
arrayOf(Data._ID, Organization.COMPANY, Organization.TITLE),
"${Data.CONTACT_ID} =? AND ${Data.MIMETYPE} = '${Organization.CONTENT_ITEM_TYPE}'",
arrayOf(contactPersonEntity.contactId),
null
)
if (organizations != null && organizations.moveToFirst()) {
do {
val organizationsEntity = OrganizationsEntity()
val companyColumnIndex = organizations.getColumnIndex(Organization.COMPANY)
val titleColumnIndex = organizations.getColumnIndex(Organization.TITLE)
organizationsEntity.company = organizations.getString(companyColumnIndex)
organizationsEntity.title = organizations.getString(titleColumnIndex)
organizationsList.add(organizationsEntity)
} while (organizations.moveToNext())
}
contactPersonEntity.organizationsEntityList = organizationsList
organizations?.close()
}
/**
* 获取联系人地址
*/
private fun getAddress(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val addressList = mutableListOf<AddressEntity>()
val address = contentResolver.query(
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI,
null,
"${ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID} = ?",
arrayOf(contactPersonEntity.contactId),
null
)
if (address != null && address.moveToFirst()) {
do {
val streetColumnIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)
val cityColumnIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)
val regionColumnIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)
val postcodeColumnIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)
val formattedAddColumnIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)
val typeIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)
val labelIndex =
address.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.LABEL)
val addressEntity = AddressEntity()
addressEntity.street = address.getString(streetColumnIndex)
addressEntity.city = address.getString(cityColumnIndex)
addressEntity.region = address.getString(regionColumnIndex)
addressEntity.postcode = address.getString(postcodeColumnIndex)
addressEntity.formatted = address.getString(formattedAddColumnIndex)
// 获取类型索引
val type = address.getInt(typeIndex)
// 根据类型设置标签
addressEntity.type = when (type) {
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME -> "住宅"
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK -> "单位"
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER -> "其他"
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_CUSTOM -> {
// 获取自定义标签
address.getString(labelIndex) ?: "自定义"
}
else -> "未知" // 如果类型未识别
}
addressList.add(addressEntity)
} while (address.moveToNext())
}
contactPersonEntity.addressEntityList = addressList
address?.close()
}
/**
* 获取IM
*/
private fun getIM(
contentResolver: ContentResolver,
context: Context,
contactPersonEntity: ContactPersonEntity,
) {
val imList = mutableListOf<IMEntity>()
val ims = contentResolver.query(
Data.CONTENT_URI,
arrayOf(Data._ID, Im.PROTOCOL, Im.CUSTOM_PROTOCOL, Im.DATA),
"${Data.CONTACT_ID} = ? AND ${Data.MIMETYPE} = '${Im.CONTENT_ITEM_TYPE}'",
arrayOf(contactPersonEntity.contactId),
null
)
if (ims != null && ims.moveToFirst()) {
do {
val imEntity = IMEntity()
val protocolColumnIndex = ims.getColumnIndex(Im.PROTOCOL)
val customProtocolColumnIndex = ims.getColumnIndex(Im.CUSTOM_PROTOCOL)
val dataColumnIndex = ims.getColumnIndex(Im.DATA)
val protocol = ims.getInt(protocolColumnIndex)
val protocolString: String? = if (protocol == Im.PROTOCOL_CUSTOM) {
// 自定义协议
ims.getString(customProtocolColumnIndex)
} else {
// 标准协议
Im.getProtocolLabel(context.resources, protocol, null)
?.toString()
}
// 如果为空则分配默认值
imEntity.imType = protocolString ?: "Unknown"
imEntity.imNumber = ims.getString(dataColumnIndex)
imList.add(imEntity)
} while (ims.moveToNext())
}
contactPersonEntity.imEntityList = imList
ims?.close()
}
/**
* 获取邮箱
*/
private fun getEmail(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val emailList = mutableListOf<EmailEntity>()
val emails = contentResolver.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
"${ContactsContract.CommonDataKinds.Email.CONTACT_ID} = ?",
arrayOf(contactPersonEntity.contactId),
null
)
if (emails != null && emails.moveToFirst()) {
do {
val emailEntity = EmailEntity()
val emailTypeIndex =
emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)
val emailDataIndex =
emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)
val labelIndex = emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.LABEL)
// 获取邮箱类型
val type = emails.getInt(emailTypeIndex)
// 根据类型设置标签
emailEntity.emailType = when (type) {
ContactsContract.CommonDataKinds.Email.TYPE_HOME -> "个人"
ContactsContract.CommonDataKinds.Email.TYPE_WORK -> "单位"
ContactsContract.CommonDataKinds.Email.TYPE_OTHER -> "其他"
ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM -> {
// 获取自定义标签
emails.getString(labelIndex) ?: "自定义"
}
else -> "未知" // 如果类型未识别
}
// 获取邮箱地址
emailEntity.emailData = emails.getString(emailDataIndex)
emailList.add(emailEntity)
} while (emails.moveToNext())
}
contactPersonEntity.emailEntityList = emailList
emails?.close()
}
/**
* 获取联系人手机号
*/
private fun getPhone(
contentResolver: ContentResolver,
contactPersonEntity: ContactPersonEntity,
) {
val phones = contentResolver.query(
Phone.CONTENT_URI,
null,
"${Phone.CONTACT_ID} = ?",
arrayOf(contactPersonEntity.contactId),
null
)
val phoneTypeList = mutableListOf<PhoneEntity>()
if (phones != null && phones.moveToFirst()) {
do {
val phoneTypeEntity = PhoneEntity()
// 获取电话类型
val phoneTypeColumnIndex = phones.getColumnIndex(Phone.TYPE)
val phoneType = if (phoneTypeColumnIndex != -1) {
phones.getInt(phoneTypeColumnIndex)
} else {
// 如果找不到类型,则默认为移动设备
Phone.TYPE_MOBILE
}
// 获取电话号码
val phoneNumberColumnIndex = phones.getColumnIndex(Phone.NUMBER)
if (phoneNumberColumnIndex != -1) {
val phoneNumber = phones.getString(phoneNumberColumnIndex)
phoneTypeEntity.phoneNumber = phoneNumber
}
// 根据类型设置标签
phoneTypeEntity.phoneType = when (phoneType) {
Phone.TYPE_HOME -> "住宅"
Phone.TYPE_WORK -> "单位"
Phone.TYPE_FAX_WORK -> "单位传真"
Phone.TYPE_FAX_HOME -> "住宅传真"
Phone.TYPE_PAGER -> "寻呼机"
Phone.TYPE_CALLBACK -> "回拨号码"
Phone.TYPE_COMPANY_MAIN -> "公司总机"
Phone.TYPE_CAR -> "车载电话"
Phone.TYPE_ISDN -> "ISDN"
Phone.TYPE_MAIN -> "总机"
Phone.TYPE_RADIO -> "无线装置"
Phone.TYPE_TELEX -> "电报"
Phone.TYPE_TTY_TDD -> "TTY_TDD"
Phone.TYPE_WORK_MOBILE -> "单位手机"
Phone.TYPE_WORK_PAGER -> "单位寻呼机"
Phone.TYPE_ASSISTANT -> "助理"
Phone.TYPE_MMS -> "彩信"
else -> "手机"
}
phoneTypeList.add(phoneTypeEntity)
} while (phones.moveToNext())
}
contactPersonEntity.phoneEntityList = phoneTypeList
phones?.close()
}
/**
* 联系人手机实体
*/
data class PhoneEntity(
var phoneType: String? = "",
var phoneNumber: String? = "",
)
/**
* 联系人IM
*/
data class IMEntity(
var imType: String? = "",
var imNumber: String? = "",
)
/**
* 联系人IM
*/
data class EmailEntity(
var emailType: String? = "",
var emailData: String? = "",
)
/**
* 联系人地址
*/
data class AddressEntity(
var street: String? = "",
var city: String? = "",
var region: String? = "",
var postcode: String? = "",
var formatted: String? = "",
var type: String? = "",
)
/**
* 联系人组织
*/
data class OrganizationsEntity(
var company: String? = "",
var title: String? = "",
)
/**
* 联系人事件
*/
data class EventEntity(
var event: String? = "",
var date: String? = "",
)
/**
* 联系人网址
*/
data class WebsiteEntity(
var url: String? = "",
var type: String? = "",
)
/**
* 联系人实体
*/
data class ContactPersonEntity(
var contactId: String = "",
// 名称
var disPlayName: String? = "",
// 备注
var noteinfo: String? = "",
// 昵称
var nickName: String? = "",
var avatar: Bitmap? = null,
var phoneEntityList: MutableList<PhoneEntity> = mutableListOf(),
var imEntityList: MutableList<IMEntity> = mutableListOf(),
var emailEntityList: MutableList<EmailEntity> = mutableListOf(),
var addressEntityList: MutableList<AddressEntity> = mutableListOf(),
var organizationsEntityList: MutableList<OrganizationsEntity> = mutableListOf(),
var eventEntityList: MutableList<EventEntity> = mutableListOf(),
var websiteEntityList: MutableList<WebsiteEntity> = mutableListOf(),
)
}