Android-এ ফোন কল শুরু করা (Intent.ACTION_DIAL vs ACTION_CALL)
Android-এ ফোন কল করার দুটি প্রধান পদ্ধতি রয়েছে: Intent.ACTION_DIAL (ডায়ালার খুলে, ব্যবহারকারী কল চাপবে) এবং Intent.ACTION_CALL (সরাসরি কল শুরু করে, বিশেষ পারমিশন দরকার)।
দুটি পদ্ধতির পার্থক্য
| ফিচার | ACTION_DIAL | ACTION_CALL |
| ব্যবহারকারী ইন্টারঅ্যাকশন | ডায়ালার খুলে, কল বাটন চাপতে হয় | সরাসরি কল শুরু হয় |
| পারমিশন | দরকার নেই | CALL_PHONE (Dangerous) |
| ব্যবহারকারীর অনুমতি | প্রতিটি কলের জন্য | একবার পারমিশন দিলে সব কল |
| সুপারিশ | ✅ সাধারণ অ্যাপের জন্য | শুধু ডায়ালার অ্যাপের জন্য |
ধাপ ১: প্রজেক্ট সেটআপ
Package: com.example.phonecalldemo
ধাপ ২: লেআউট (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ফোন কল ডেমো"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp"/>
<EditText
android:id="@+id/etPhoneNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="ফোন নম্বর লিখুন"
android:inputType="phone"
android:text="01700000000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/btnDial"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:text="ডায়ালার খুলুন (ACTION_DIAL)"
android:onClick="openDialer"/>
<Button
android:id="@+id/btnCall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="সরাসরি কল (ACTION_CALL)"
android:onClick="makeDirectCall"
android:backgroundTint="#F44336"
android:textColor="#FFFFFF"/>
</LinearLayout>
<TextView
android:id="@+id/tvStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:textSize="14sp"
android:textColor="#666"/>
</LinearLayout>
ধাপ ৩: MainActivity.java
package com.example.phonecalldemo;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CALL_PERMISSION = 101;
private EditText etPhoneNumber;
private TextView tvStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etPhoneNumber = findViewById(R.id.etPhoneNumber);
tvStatus = findViewById(R.id.tvStatus);
}
// পদ্ধতি ১: ACTION_DIAL - কোনো পারমিশন দরকার নেই
public void openDialer(View view) {
String phoneNumber = etPhoneNumber.getText().toString().trim();
if (phoneNumber.isEmpty()) {
tvStatus.setText("দয়া করে ফোন নম্বর লিখুন");
return;
}
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
dialIntent.setData(Uri.parse("tel:" + phoneNumber));
// অ্যাপ্লিকেশন চয়ারার দেখাবে (ডায়ালার, স্কাইপ, WhatsApp, ইত্যাদি)
if (dialIntent.resolveActivity(getPackageManager()) != null) {
startActivity(dialIntent);
tvStatus.setText("ডায়ালার খুলেছে: " + phoneNumber);
} else {
tvStatus.setText("কোনো ডায়ালার অ্যাপ পাওয়া যায়নি");
}
}
// পদ্ধতি ২: ACTION_CALL - CALL_PHONE পারমিশন দরকার
public void makeDirectCall(View view) {
String phoneNumber = etPhoneNumber.getText().toString().trim();
if (phoneNumber.isEmpty()) {
tvStatus.setText("দয়া করে ফোন নম্বর লিখুন");
return;
}
// রানটাইম পারমিশন চেক (Android 6.0+)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
// পারমিশন রিকোয়েস্ট
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE},
REQUEST_CALL_PERMISSION);
tvStatus.setText("কল পারমিশন প্রয়োজন। অনুমতি দিন।");
return;
}
// পারমিশন আছে -> সরাসরি কল
placeCall(phoneNumber);
}
private void placeCall(String phoneNumber) {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + phoneNumber));
if (callIntent.resolveActivity(getPackageManager()) != null) {
startActivity(callIntent);
tvStatus.setText("কল শুরু হয়েছে: " + phoneNumber);
} else {
tvStatus.setText("কল হ্যান্ডলার পাওয়া যায়নি");
}
}
// পারমিশন রিকোয়েস্ট রিজাল্ট হ্যান্ডল
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CALL_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
String phoneNumber = etPhoneNumber.getText().toString().trim();
placeCall(phoneNumber);
} else {
tvStatus.setText("কল পারমিশন অস্বীকৃত হয়েছে। সেটিংস থেকে দিন।");
Toast.makeText(this, "কল করার জন্য ফোন কল পারমিশন আবশ্যক", Toast.LENGTH_LONG).show();
}
}
}
}
ধাপ ৪: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.phonecalldemo">
<!-- ACTION_DIAL-এ কোনো পারমিশন লাগে না -->
<!-- ACTION_CALL-এ এই পারমিশন বাধ্যতামূলক -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PhoneCallDemo">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Uri ফরম্যাটিং টিপস
// সিম্পল নম্বর
Uri.parse("tel:01700000000")
// আন্তর্জাতিক ফরম্যাট (দেশ কোড সহ)
Uri.parse("tel:+8801700000000")
// পজ, ভয়েস মেইল এক্সটেনশন (কিছু ক্যারিয়ার সাপোর্ট করে)
Uri.parse("tel:01700000000,,1234#") // ১২৩৪ এক্সটেনশন, পজ দিয়ে
// USSD কোড (ব্যালেন্স চেক, ইত্যাদি) - ACTION_DIAL দিয়ে কাজ করে
Uri.parse("tel:*123%23") // *123# ( %23 = # )
Android 11+ (API 30+) Package Visibility
Android 11 থেকে অ্যাপগুলো একে অপরের ইন্টেন্ট রিজল্ভ করতে পারে না যদি <queries> ডিক্লেয়ার না করা হয়। ডায়ালার অ্যাপ খোলার জন্য:
<manifest ...>
<queries>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.CALL" />
<data android:scheme="tel" />
</intent>
</queries>
...
</manifest>
সাধারণ সমস্যা ও সমাধান
| সমস্যা | সমাধান |
| ACTION_CALL ক্র্যাশ হয় | CALL_PHONE পারমিশন manifest-এ এবং রানটাইমে granted আছে কিনা চেক করুন |
| ডায়ালার খুলছে না | PackageManager.resolveActivity() null রিটার্ন করলে কোনো ডায়ালার অ্যাপ নেই |
| Android 11+ এ ডায়ালার খুলছে না | Manifest-এ <queries> ব্লক যোগ করুন (উপরে দেখানো) |
| USSD কোড কাজ করে না | # ক্যারেক্টার URL-এনকোড করুন (%23), ACTION_DIAL ব্যবহার করুন |
সেরা অনুশীলন
- সাধারণ অ্যাপের জন্য ACTION_DIAL ব্যবহার করুন — ব্যবহারকারীর নিয়ন্ত্রণ থাকে, কোনো পারমিশন লাগে না
- ফোন নম্বর ইনপুট ভ্যালিডেশন করুন (Regex:
^[+]?[0-9]{10,15}$)
- ইমার্জেন্সি নম্বর (999, 112, 911) ব্লক/হ্যান্ডেল করুন আলাদাভাবে
- ডুয়াল সিম ডিভাইসে সিম নির্বাচন ডায়ালার অ্যাপে থাকে