I'm trying to get some information about a contact that the user can select in the contact list, using Kotlin. I tried a couple tutorials that only worked partly. This is the code that should call startActivityForResult(), from MainActivity.kt
:
add_contact.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
startActivityForResult(intent, CONTACT_PICK_CODE)
}
And the following is the overridden onActivityResult
method:
@SuppressLint("Range")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// handle intent results || calls when user from Intent (Contact Pick) picks or cancels pick contact
if (resultCode == RESULT_OK) {
if (requestCode == CONTACT_PICK_CODE) {
val cursor1: Cursor
val cursor2: Cursor?
// get data from intent
val uri = data!!.data
cursor1 = contentResolver.query(uri!!, null, null, null, null)!!
if (cursor1.moveToFirst()) {
// get contact details
val contactId = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID))
val contactName = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
val contactThumbnail = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))
val idResults = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))
val idResultHold = idResults.toInt()
// check if contact has a phone number or not
if (idResultHold == 1) {
cursor2 = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID " = " contactId,
null,
null
)
// a contact may have multiple phone numbers
var contactNumber : String = ""
while (cursor2!!.moveToNext()) {
// get phone number
contactNumber = cursor2.getString(cursor2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
}
Toast.makeText(this, "Contact number: $contactNumber", Toast.LENGTH_SHORT).show()
cursor2.close()
}
cursor1.close()
}
}
} else {
Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show()
}
}
The line that prints "Contact number: ..." never prints the contact number, which means that the while
loop never runs.
All the other variables (contactId
, contactName
...) seem to be assigned the correct value every time, but the number doesn't. Does anyone know what causes that to happen?
CodePudding user response:
Try this to get multiple phone numbers from a contact
const val REQUEST_SELECT_PHONE_NUMBER = 1
fun selectContact() {
// Start an activity for the user to pick a phone number from contacts
val intent = Intent(Intent.ACTION_PICK).apply {
type = CommonDataKinds.Phone.CONTENT_TYPE
}
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == Activity.RESULT_OK) {
// Get the URI and query the content provider for the phone number
val contactUri: Uri = data.data
val projection: Array<String> = arrayOf(CommonDataKinds.Phone.NUMBER)
contentResolver.query(contactUri, projection, null, null, null).use { cursor ->
// If the cursor returned is valid, get the phone number
if (cursor.moveToFirst()) {
val numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER)
val number = cursor.getString(numberIndex)
// Do something with the phone number
...
}
}
}
}
CodePudding user response:
cursor2 = > contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, ...
To return the phone numbers you need to replace the ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI
Uri with ContactsContract.CommonDataKinds.Phone.CONTENT_URI
Instead of using a String, you can use a Set
to have no duplicate numbers, because; this URI returns all the links to the phone numbers besides the phone storage; like Google, WhatsApp, .. etc.
@SuppressLint("Range")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// handle intent results || calls when user from Intent (Contact Pick) picks or cancels pick contact
if (resultCode == RESULT_OK) {
if (requestCode == CONTACT_PICK_CODE) {
val cursor1: Cursor
val cursor2: Cursor?
// get data from intent
val uri = data!!.data
cursor1 = contentResolver.query(uri!!, null, null, null, null)!!
if (cursor1.moveToFirst()) {
// get contact details
val contactId =
cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID))
val contactName =
cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
val contactThumbnail =
cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))
val idResults =
cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))
val idResultHold = idResults.toInt()
// check if contact has a phone number or not
if (idResultHold == 1) {
cursor2 = contentResolver.query(
// ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, // WRONG
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID " = " contactId,
null,
null
)
// a contact may have multiple phone numbers
val numbers = mutableSetOf<String>()
cursor2?.let {
while (cursor2.moveToNext()) {
val phoneNumber =
cursor2.getString(
cursor2.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER
)
).replace("-", "").replace(
" ",
""
) // Remove the dash sign & spaces from the numbers
numbers.add(phoneNumber)
}
Toast.makeText(
this@MainActivity,
"$contactName $numbers",
Toast.LENGTH_LONG
).show()
cursor2.close()
}
cursor1.close()
}
}
}
} else {
Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show()
}
}
Note: you're using a deprecated API onActivityResult
that is replaced with registerForActivityResult
Here is a demo of using it:
class MainActivity : AppCompatActivity() {
private val requestSinglePermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
// Do something if permission granted
if (isGranted) {
Log.d("LOG_TAG", "permission granted by the user")
// Do something as the permission is not granted
} else {
Log.d("LOG_TAG", "permission denied by the user")
}
}
private var allNumLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data = result.data?.data
data?.let {
val cursor = contentResolver.query(
data,
null,
null,
null,
null
)
cursor?.let {
if (it.moveToFirst()) {
val name =
it.getString(it.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))
if (Integer.parseInt(
it.getString(
it.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER
)
)
) > 0 // Check if the contact has phone numbers
) {
val id =
it.getString(it.getColumnIndex(ContactsContract.Contacts._ID))
val phonesCursor = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID " = " id,
null,
null
)
val numbers = mutableSetOf<String>()
phonesCursor?.let {
while (phonesCursor.moveToNext()) {
val phoneNumber =
phonesCursor.getString(
phonesCursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER
)
).replace("-", "").replace(" ", "")
numbers.add(phoneNumber)
}
Toast.makeText(
this@MainActivity,
"$name $numbers",
Toast.LENGTH_LONG
).show()
Log.d(TAG, "$name $numbers")
}
phonesCursor?.close()
} else {
Toast.makeText(
this@MainActivity,
"$name - No numbers",
Toast.LENGTH_LONG
).show()
Log.d(TAG, "$name - No numbers")
}
}
cursor.close()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_CONTACTS
) != PackageManager.PERMISSION_GRANTED
) {
requestSinglePermission.launch(
Manifest.permission.READ_CONTACTS
)
}
// get a contact:
val intent = Intent(Intent.ACTION_PICK,
ContactsContract.Contacts.CONTENT_URI)
allNumLauncher.launch(intent)
}
}