যোগাযোগ পিকার

অ্যান্ড্রয়েড কন্টাক্ট পিকার হলো একটি প্রমিত, ব্রাউজযোগ্য ইন্টারফেস, যার মাধ্যমে ব্যবহারকারীরা আপনার অ্যাপের সাথে কন্টাক্ট শেয়ার করতে পারেন। অ্যান্ড্রয়েড ১৭ (এপিআই লেভেল ৩৭) বা তার উচ্চতর সংস্করণে চালিত ডিভাইসগুলোতে উপলব্ধ এই পিকারটি, ব্যাপক READ_CONTACTS পারমিশনের একটি গোপনীয়তা-সংরক্ষক বিকল্প প্রদান করে। ব্যবহারকারীর সম্পূর্ণ অ্যাড্রেস বুকে অ্যাক্সেসের অনুরোধ করার পরিবর্তে, আপনার অ্যাপটি তার প্রয়োজনীয় ডেটা ফিল্ডগুলো, যেমন ফোন নম্বর বা ইমেল অ্যাড্রেস, নির্দিষ্ট করে দেয় এবং ব্যবহারকারী শেয়ার করার জন্য নির্দিষ্ট কন্টাক্ট নির্বাচন করেন। এটি আপনার অ্যাপকে শুধুমাত্র নির্বাচিত ডেটাতে রিড অ্যাক্সেস দেয়, যা ইউআই তৈরি বা রক্ষণাবেক্ষণ না করেই বিল্ট-ইন সার্চ, প্রোফাইল পরিবর্তন এবং একাধিক কন্টাক্ট নির্বাচনের সুবিধার মাধ্যমে একটি সামঞ্জস্যপূর্ণ ব্যবহারকারীর অভিজ্ঞতা প্রদান করে এবং এর মাধ্যমে সূক্ষ্ম নিয়ন্ত্রণ নিশ্চিত করে।

কন্টাক্ট পিকার একীভূত করুন

কন্টাক্ট পিকার ইন্টিগ্রেট করতে, Intent.ACTION_PICK_CONTACTS ইন্টেন্টটি ব্যবহার করুন। এই ইন্টেন্টটি পিকারটি চালু করে এবং নির্বাচিত কন্টাক্টগুলো আপনার অ্যাপে ফেরত পাঠায়।

পুরোনো ACTION_PICK থেকে ভিন্ন, কন্টাক্ট পিকার আপনাকে একই সাথে আপনার অ্যাপের জন্য প্রয়োজনীয় একাধিক ডেটা ফিল্ড নির্দিষ্ট করার সুযোগ দেয়। এটি করার জন্য আপনাকে Intent.EXTRA_REQUESTED_DATA_FIELDS ব্যবহার করতে হবে এবং ContactsContract.CommonDataKinds এ সংজ্ঞায়িত MIME টাইপগুলোর একটি ArrayList<String> পাস করতে হবে।

সাধারণ MIME প্রকারগুলির মধ্যে রয়েছে:

  • ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
  • ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
  • ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE

পিকারটি চালু করুন

পিকারটি চালু করতে StartActivityForResult কন্ট্রাক্টের সাথে registerForActivityResult ব্যবহার করুন। আপনি একক বা একাধিক নির্বাচনের অনুমতি দেওয়ার জন্য ইন্টেন্টটি কনফিগার করতে পারেন।

// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
    if (it.resultCode == Activity.RESULT_OK) {
        val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult

        // Process the result URI in a background thread to fetch all selected contacts
        coroutine.launch {
            contacts = processContactPickerResultUri(resultUri, context)
        }
    }
}

নির্বাচন মোড

অনুরোধ করা ডেটা ফিল্ড অনুযায়ী কন্টাক্ট পিকারের ইউজার ইন্টারফেস (UI) পরিবর্তিত হয়। এই প্রয়োজনীয়তার উপর নির্ভর করে, ব্যবহারকারীরা একাধিক ফিল্ডের প্রয়োজন হলে সম্পূর্ণ কন্টাক্ট রেকর্ডটি বেছে নিতে পারেন, অথবা কোনো কন্টাক্টের তথ্যের মধ্য থেকে নির্দিষ্ট ডেটা আইটেম নির্বাচন করতে পারেন।

কন্টাক্ট পিকারের বিভিন্ন UI মোড
চিত্র ১. কন্টাক্ট পিকার ইন্টারফেসটি অনুরোধকৃত ডেটা ফিল্ড অনুযায়ী (একক কন্টাক্ট, একাধিক কন্টাক্ট এবং একাধিক ফোন নম্বর নির্বাচন) নিজেকে মানিয়ে নেয়।

একটিমাত্র পরিচিতি নির্বাচন করুন

এই উদাহরণে, অ্যাপটি শুধুমাত্র ফোন নম্বর চায়। পিকারটি তালিকাটি ফিল্টার করে শুধু ফোন নম্বরসহ কন্ট্যাক্টগুলো দেখাবে এবং ব্যবহারকারীকে একটি নির্দিষ্ট নম্বর বেছে নিতে দেবে।

// Define the specific contact data fields you need
val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
}

// Launch the picker
pickContact.launch(pickContactIntent)

একাধিক পরিচিতি নির্বাচন করুন

একাধিক আইটেম বেছে নেওয়ার সুবিধা চালু করতে, Intent.EXTRA_ALLOW_MULTIPLE এক্সট্রাটি যোগ করুন। আপনি চাইলে একজন ব্যবহারকারী কতগুলো আইটেম বেছে নিতে পারবে, তা সীমিত করতে পারেন।

val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    // Enable multi-select
    putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    // Set limit of selectable contacts
    putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
    // Define the specific contact data fields you need
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
    // Enable this option to only filter contacts that have all the requested data fields
    putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}

// Launch the picker
pickContact.launch(pickContactIntent)

ফলাফলগুলো সামলান।

ব্যবহারকারী নির্বাচন সম্পন্ন করলে, সিস্টেম একটি RESULT_OK এবং একটি সেশন ইউআরআই (Session URI) ফেরত দেয়। এই ইউআরআই নির্বাচিত ডেটাতে অস্থায়ী পঠন অ্যাক্সেস প্রদান করে।

আপনি একটি স্ট্যান্ডার্ড ContentResolver ব্যবহার করে এই URI-টি কোয়েরি করতে পারেন। এর ফলে প্রাপ্ত Cursor অনুরোধ করা ডেটা ফিল্ডগুলো থাকে এবং এটি ContactsContract.Data এর স্কিমা অনুসরণ করে।

// Data class representing a parsed Contact with selected details.
data class Contact(
    val lookupKey: String,
    val name: String,
    val emails: List<String>,
    val phones: List<String>
)

// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number.
private suspend fun processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): List<Contact> = withContext(Dispatchers.IO) {
    // Define the columns we want to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
        ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
    )

    // We use `LOOKUP_KEY` as a unique ID to aggregate all contact info related to a same person
    val contactsMap = mutableMapOf<String, Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    // We query the URI directly to get the results chosen by the user.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val lookupKeyIdx = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)

        while (cursor.moveToNext()) {
            val lookupKey = cursor.getString(lookupKeyIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            val existingContact = contactsMap[lookupKey]
            if (existingContact != null) {
                contactsMap[lookupKey] = existingContact.copy(
                    emails = if (email != null) existingContact.emails + email else existingContact.emails,
                    phones = if (phone != null) existingContact.phones + phone else existingContact.phones
                )
            } else {
                contactsMap[lookupKey] = Contact(
                    lookupKey = lookupKey,
                    name = name,
                    emails = if (email != null) listOf(email) else emptyList(),
                    phones = if (phone != null) listOf(phone) else emptyList()
                )
            }
        }
    }

    return@withContext contactsMap.values.toList()
}

পশ্চাৎ সামঞ্জস্যতা

অ্যান্ড্রয়েড ১৭ (এপিআই লেভেল ৩৭) এবং তার পরবর্তী সংস্করণের জন্য তৈরি অ্যাপগুলোর ক্ষেত্রে, সিস্টেম স্বয়ংক্রিয়ভাবে বিদ্যমান Intent.ACTION_PICK ইন্টেন্টটিকে নতুন কন্টাক্ট পিকার ইন্টারফেস ব্যবহার করার জন্য আপগ্রেড করে দেয়।

আপনার অ্যাপে যদি আগে থেকেই ACTION_PICK ব্যবহৃত হয়ে থাকে, তাহলে নতুন UI গ্রহণ করার জন্য আপনার কোড পরিবর্তন করার প্রয়োজন নেই। তবে, নতুন ফিচারগুলোর সুবিধা নিতে, যেমন কন্ট্যাক্ট ডেটা কোয়েরি করার জন্য একটিমাত্র Uri গ্রহণ করা, ব্যক্তিগত ও কর্মক্ষেত্রের প্রোফাইলের মধ্যে পরিবর্তন করা অথবা একাধিক ডেটা ফিল্ডের জন্য অনুরোধ করা, আপনাকে অবশ্যই আপনার ইমপ্লিমেন্টেশন আপডেট করে Intent.ACTION_PICK_CONTACTS অথবা নতুন ইন্টেন্ট এক্সট্রাগুলো ব্যবহার করতে হবে।

পুরানো টার্গেট SDK-গুলিতে পরীক্ষা করা হচ্ছে

আপনার অ্যাপ যদি নিম্নতর SDK সংস্করণকে টার্গেট করেও থাকে, তবুও আপনার ACTION_PICK ইন্টেন্টে EXTRA_USE_SYSTEM_CONTACTS_PICKER বুলিয়ান এক্সট্রাটি যোগ করে আপনি Android 17 বা তার উচ্চতর সংস্করণের ডিভাইসগুলিতে নতুন পিকারের আচরণ পরীক্ষা করতে পারেন।

সর্বোত্তম অনুশীলন

  • শুধু আপনার প্রয়োজনীয় জিনিসটির জন্যই অনুরোধ করুন : যদি আপনার অ্যাপের শুধু একটি SMS পাঠানোর প্রয়োজন হয়, তাহলে Phone.CONTENT_ITEM_TYPE জন্য অনুরোধ করুন। পিকারটি স্বয়ংক্রিয়ভাবে সেইসব কন্ট্যাক্ট ফিল্টার করে দেবে যাদের ফোন নম্বর নেই, ফলে ব্যবহারকারীর জন্য UI আরও পরিচ্ছন্ন দেখাবে।
  • প্রতিটি কন্ট্যাক্টের জন্য একাধিক ডেটা এন্ট্রি পরিচালনা করা : প্রতিটি কন্ট্যাক্টে প্রায়শই বিভিন্ন ইমেল অ্যাড্রেস বা ফোন নম্বর থাকে। ব্যবহারকারীর কাছে এগুলি যাতে স্পষ্টভাবে এবং সহজে বোধগম্যভাবে উপস্থাপন করা যায়, তা নিশ্চিত করতে ContactsContract.Contacts.LOOKUP_KEY ব্যবহার করে সেগুলিকে গ্রুপ করার পরামর্শ দেওয়া হয়। এছাড়াও, আপনার অ্যাপের ইন্টারফেসে আরও সূক্ষ্মভাবে বাছাই করার সুযোগ দিতে, আপনি প্রতিটি এন্ট্রির জন্য নির্দিষ্ট লেবেল (যেমন কর্মক্ষেত্র বা ব্যক্তিগত) ব্যবহার করতে পারেন।
  • ডেটা অবিলম্বে সংরক্ষণ করুন : সেশন ইউআরআই অস্থায়ীভাবে পড়ার অনুমতি দেয়। যদি আপনার পরে (আপনার অ্যাপ প্রসেস বন্ধ হয়ে যাওয়ার পর) এই যোগাযোগের তথ্য অ্যাক্সেস করার প্রয়োজন হয়, তবে আপনার অ্যাপকে যোগাযোগের ডেটা সংরক্ষণ করতে হবে।
  • অ্যাকাউন্ট ডেটার উপর নির্ভর করবেন না : ব্যবহারকারীর গোপনীয়তা রক্ষা করতে এবং ফিঙ্গারপ্রিন্টিং প্রতিরোধ করতে, ফলাফল থেকে অ্যাকাউন্ট-নির্দিষ্ট মেটাডেটা মুছে ফেলা হয়।