Tổng quan về giao thức khởi tạo phiên

Phát hiện eSIM và thẻ SIM

Phát hiện thẻ

Thiết bị Android có thẻ SIM và eSIM sử dụng các mã nhận dạng sau trong điện thoại API, bao gồm [`TelephonyManager`](/reference/android/telephony/TelephonyManager) và [`SubscriptionManager`](/reference/android/telephony/SubscriptionManager): * Mã nhận dạng gói thuê bao: mã nhận dạng duy nhất của một gói thuê bao di động. * Chỉ mục hoặc mã nhận dạng khe logic: chỉ mục duy nhất tham chiếu đến một khe cắm SIM logic. ID vị trí logic bắt đầu từ 0 và tăng lên tùy thuộc vào số lượng các vị trí đang hoạt động được hỗ trợ trên thiết bị. Ví dụ: thiết bị hai SIM thường có khe 0 và khe 1. Nếu thiết bị có nhiều khe cắm thực tế nhưng chỉ hỗ trợ một vị trí đang hoạt động, nó sẽ chỉ có ID vị trí logic 0. * Chỉ mục hoặc mã nhận dạng vị trí thực tế: chỉ mục duy nhất tham chiếu đến một khe SIM thực. Mã khung giờ thực tế bắt đầu từ 0 và tăng lên tuỳ thuộc vào số lượng đường liên kết vật lý các khe trên thiết bị. Số lượng này khác với số lượng khe logic mà một thiết bị có, tương ứng với số lượng khe đang hoạt động mà một thiết bị có thể đang sử dụng. Ví dụ: một thiết bị chuyển đổi giữa hai SIM và một SIM nhưng ở chế độ một SIM, chế độ này có thể luôn có 2 khe cắm vật lý một khe logic. * Mã thẻ: mã nhận dạng duy nhất dùng để nhận dạng một UiccCard. ![Sơ đồ về cách sử dụng mã nhận dạng trong trường hợp có 2 ô logic và 3 ô thực](/images/guide/topics/mạc/tel-ids.png) Trong biểu đồ trên: * Thiết bị có 2 khe logic. * Trong ô 0 thực có một thẻ UICC thực với hồ sơ đang hoạt động. * Trong ô thực tế 2 là một eUICC có hồ sơ đang hoạt động. * Khe thực 1 hiện không được sử dụng. ![Sơ đồ cách sử dụng mã nhận dạng trong trường hợp có 3 ô logic và 2 ô thực](/images/guide/topics/mạc/tel-ids-2.png) Trong biểu đồ trên: * Thiết bị có 3 khe logic. * Trong ô 0 thực có một thẻ UICC thực với hồ sơ đang hoạt động. * Trong ô thực tế 1 là một eUICC có 2 cấu hình đã tải xuống, cả hai đều hoạt động bằng MEP (Nhiều cấu hình đã bật).

Tổng quan về giao thức khởi tạo phiên

Android cung cấp một API hỗ trợ Giao thức khởi tạo phiên (SIP). Việc này cho phép bạn thêm các tính năng của điện thoại Internet dựa trên SIP vào ứng dụng của mình. Android có ngăn xếp giao thức SIP đầy đủ và tính năng quản lý cuộc gọi tích hợp các dịch vụ cho phép ứng dụng dễ dàng thiết lập các cuộc gọi thoại đến và đi, mà không phải quản lý các phiên, thông tin giao tiếp cấp độ truyền tải hoặc âm thanh ghi hoặc phát trực tiếp.

Dưới đây là ví dụ về các loại ứng dụng có thể sử dụng API SIP:

  • Hội nghị truyền hình
  • Nhắn tin tức thì

Yêu cầu và giới hạn

Sau đây là các yêu cầu để phát triển ứng dụng SIP:

  • Bạn phải có thiết bị di động chạy Android 2.3 trở lên.
  • SIP chạy qua kết nối dữ liệu không dây, nên thiết bị của bạn phải có dữ liệu kết nối (qua dịch vụ dữ liệu di động hoặc Wi-Fi). Điều này có nghĩa là bạn không thể kiểm thử trên AVD – bạn chỉ có thể kiểm thử trên một thiết bị thực. Để biết thông tin chi tiết, hãy xem Thử nghiệm ứng dụng SIP.
  • Mỗi người tham gia trong phiên giao tiếp của ứng dụng phải có Tài khoản SIP. Có nhiều nhà cung cấp SIP cung cấp tài khoản SIP.

Lưu ý: Thư viện android.net.sip không hỗ trợ video cuộc gọi. Nếu bạn muốn triển khai tính năng gọi VOIP bằng cách sử dụng ngăn xếp SIP, chẳng hạn như android.net.sip, hãy xem xét một trong nhiều nguồn mở hiện đại các phương án thay thế làm cơ sở cho bất kỳ việc triển khai lệnh gọi VOIP nào. Ngoài ra, bạn có thể triển khai ConnectionService API để tích hợp chặt chẽ các lệnh gọi này vào Trình quay số của thiết bị .

Các lớp và giao diện API SIP

Dưới đây là bản tóm tắt về các lớp và một giao diện (SipRegistrationListener) có trong Android SIP API:

Lớp/Giao diện Mô tả
SipAudioCall Xử lý cuộc gọi âm thanh trên Internet qua SIP.
SipAudioCall.Listener Trình nghe các sự kiện liên quan đến cuộc gọi SIP, chẳng hạn như khi một cuộc gọi đang được thực hiện đã nhận ("khi đổ chuông") hoặc một cuộc gọi đang đi ("khi gọi").
SipErrorCode Xác định mã lỗi được trả về trong các thao tác SIP.
SipManager Cung cấp API cho các tác vụ SIP, chẳng hạn như khởi tạo kết nối SIP và cung cấp quyền truy cập sang các dịch vụ SIP có liên quan.
SipProfile Xác định hồ sơ SIP, bao gồm thông tin tài khoản SIP, miền và máy chủ.
SipProfile.Builder Lớp trợ giúp để tạo SipProfile.
SipSession Biểu thị một phiên SIP liên kết với hộp thoại SIP hoặc một giao dịch độc lập không phải trong hộp thoại.
SipSession.Listener Trình nghe các sự kiện liên quan đến một phiên SIP, chẳng hạn như khi một phiên đang được đăng ký ("khi đăng ký") hoặc là một cuộc gọi đi ("khi đang gọi").
SipSession.State Xác định trạng thái phiên SIP, chẳng hạn như "đăng ký", "cuộc gọi đi" và "đang gọi".
SipRegistrationListener Giao diện là trình nghe sự kiện đăng ký SIP.

Đang tạo tệp kê khai

Nếu bạn đang phát triển một ứng dụng sử dụng API SIP, hãy nhớ rằng Tính năng này chỉ được hỗ trợ trên Android 2.3 (API cấp 9) trở lên của nền tảng. Ngoài ra, trong số các thiết bị chạy Android 2.3 (API cấp 9) trở lên, không phải mọi thiết bị đều hỗ trợ SIP.

Để sử dụng SIP, hãy thêm các quyền sau đây vào tệp kê khai của ứng dụng:

  • android.permission.USE_SIP
  • android.permission.INTERNET

Để đảm bảo rằng ứng dụng của bạn chỉ có thể được cài đặt trên các thiết bị có khả năng hỗ trợ SIP, hãy thêm đoạn mã sau vào tệp kê khai:

<uses-sdk android:minSdkVersion="9" />

Điều này cho biết ứng dụng của bạn yêu cầu Android 2.3 trở lên. Cho thông tin khác, xem Cấp độ API và tài liệu cho <uses-sdk> .

Để kiểm soát cách lọc ứng dụng khỏi các thiết bị không hỗ trợ SIP (ví dụ: trên Google Play), hãy thêm đoạn mã sau vào tệp kê khai:

<uses-feature android:name="android.software.sip.voip" />

Điều này cho biết ứng dụng của bạn sử dụng API SIP. Nội dung khai báo phải thêm thuộc tính android:required cho biết liệu bạn muốn lọc ứng dụng khỏi các thiết bị không hỗ trợ SIP. Bạn cũng có thể cần khai báo <uses-feature> khác, tuỳ thuộc vào cách triển khai của bạn. Để biết thêm thông tin, hãy xem tài liệu cho <uses-feature> .

Nếu ứng dụng được thiết kế để nhận lệnh gọi, bạn cũng phải xác định trình nhận (lớp con BroadcastReceiver) trong tệp kê khai của ứng dụng:

<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />

Dưới đây là các phần trích dẫn từ tệp kê khai Sipdemo:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.android.sip">
  ...
     <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
  ...
  <uses-sdk android:minSdkVersion="9" />
  <uses-permission android:name="android.permission.USE_SIP" />
  <uses-permission android:name="android.permission.INTERNET" />
  ...
  <uses-feature android:name="android.software.sip.voip" android:required="true" />
  <uses-feature android:name="android.hardware.wifi" android:required="true" />
  <uses-feature android:name="android.hardware.microphone" android:required="true" />
</manifest>

Tạo SipManager

Để sử dụng API SIP, ứng dụng của bạn phải tạo đối tượng SipManager. SipManager sẽ lấy hãy quan tâm đến những điều sau trong ứng dụng của bạn:

  • Đang bắt đầu các phiên SIP.
  • Thực hiện và nhận cuộc gọi.
  • Đăng ký và huỷ đăng ký với nhà cung cấp SIP.
  • Đang xác minh kết nối phiên.

Bạn tạo thực thể cho SipManager mới như sau:

Kotlin

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

Java

public SipManager sipManager = null;
...
if (sipManager == null) {
    sipManager = SipManager.newInstance(this);
}

Đăng ký bằng Máy chủ SIP

Một ứng dụng Android SIP điển hình liên quan đến một hoặc nhiều người dùng, mỗi người trong số họ có tài khoản SIP. Trong ứng dụng Android SIP, mỗi tài khoản SIP được biểu thị bằng một đối tượng SipProfile.

SipProfile xác định hồ sơ SIP, bao gồm cả SIP tài khoản, tên miền và thông tin máy chủ. Hồ sơ đã liên kết với SIP trên thiết bị chạy ứng dụng được gọi là local hồ sơ. Cấu hình mà phiên được kết nối được gọi là hồ sơ ngang hàng. Khi ứng dụng SIP của bạn đăng nhập vào máy chủ SIP bằng SipProfile cục bộ, điều này sẽ đăng ký hiệu quả làm vị trí để gửi cuộc gọi SIP tới địa chỉ SIP của bạn.

Phần này trình bày cách tạo SipProfile, đăng ký với máy chủ SIP và theo dõi các sự kiện đăng ký.

Bạn sẽ tạo một đối tượng SipProfile như sau:

Kotlin

private var sipProfile: SipProfile? = null
...

val builder = SipProfile.Builder(username, domain)
        .setPassword(password)
sipProfile = builder.build()

Java

public SipProfile sipProfile = null;
...

SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword(password);
sipProfile = builder.build();

Phần trích dẫn mã sau đây sẽ mở hồ sơ cục bộ để thực hiện cuộc gọi và/hoặc nhận các cuộc gọi SIP chung. Người gọi có thể thực hiện các cuộc gọi tiếp theo thông qua mSipManager.makeAudioCall. Phần trích dẫn này cũng đặt hành động android.SipDemo.INCOMING_CALL (sẽ được một ý định sử dụng) khi thiết bị nhận được cuộc gọi (xem phần Thiết lập bộ lọc ý định để nhận cuộc gọi). Đây là bước đăng ký:

Kotlin

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open(sipProfile, pendingIntent, null)

Java

Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
sipManager.open(sipProfile, pendingIntent, null);

Cuối cùng, mã này đặt SipRegistrationListener trên SipManager. Thao tác này sẽ theo dõi xem SipProfile đã được đăng ký thành công với dịch vụ SIP của bạn hay chưa nhà cung cấp:

Kotlin

sipManager?.setRegistrationListener(sipProfile?.uriString, object : SipRegistrationListener {

    override fun onRegistering(localProfileUri: String) {
        updateStatus("Registering with SIP Server...")
    }

    override fun onRegistrationDone(localProfileUri: String, expiryTime: Long) {
        updateStatus("Ready")
    }

    override fun onRegistrationFailed(
            localProfileUri: String,
            errorCode: Int,
            errorMessage: String
    ) {
        updateStatus("Registration failed. Please check settings.")
    }
})

Java

sipManager.setRegistrationListener(sipProfile.getUriString(), new SipRegistrationListener() {

    public void onRegistering(String localProfileUri) {
        updateStatus("Registering with SIP Server...");
    }

    public void onRegistrationDone(String localProfileUri, long expiryTime) {
        updateStatus("Ready");
    }

    public void onRegistrationFailed(String localProfileUri, int errorCode,
        String errorMessage) {
        updateStatus("Registration failed.  Please check settings.");
    }
}

Khi ứng dụng của bạn hoàn tất quá trình sử dụng hồ sơ, hồ sơ sẽ đóng hồ sơ để giải phóng đối tượng được liên kết vào bộ nhớ và huỷ đăng ký thiết bị khỏi máy chủ. Ví dụ:

Kotlin

fun closeLocalProfile() {
    try {
        sipManager?.close(sipProfile?.uriString)
    } catch (ee: Exception) {
        Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee)
    }
}

Java

public void closeLocalProfile() {
    if (sipManager == null) {
       return;
    }
    try {
       if (sipProfile != null) {
          sipManager.close(sipProfile.getUriString());
       }
     } catch (Exception ee) {
       Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
     }
}

Gọi thoại

Để thực hiện cuộc gọi thoại, bạn phải có sẵn những thiết bị sau:

  • SipProfile đang thực hiện cuộc gọi ( "local profile") và một địa chỉ SIP hợp lệ để nhận cuộc gọi ( "hồ sơ ngang hàng").
  • Đối tượng SipManager.

Để thực hiện cuộc gọi thoại, bạn nên thiết lập SipAudioCall.Listener. Phần lớn hoạt động tương tác của khách hàng với ngăn xếp SIP diễn ra thông qua trình nghe. Trong đoạn mã này, bạn sẽ thấy cách SipAudioCall.Listener thiết lập mọi thứ sau khi cuộc gọi được thực hiện thiết lập:

Kotlin

var listener: SipAudioCall.Listener = object : SipAudioCall.Listener() {

    override fun onCallEstablished(call: SipAudioCall) {
        call.apply {
            startAudio()
            setSpeakerMode(true)
            toggleMute()
        }
    }

    override fun onCallEnded(call: SipAudioCall) {
        // Do something.
    }
}

Java

SipAudioCall.Listener listener = new SipAudioCall.Listener() {

   @Override
   public void onCallEstablished(SipAudioCall call) {
      call.startAudio();
      call.setSpeakerMode(true);
      call.toggleMute();
         ...
   }

   @Override

   public void onCallEnded(SipAudioCall call) {
      // Do something.
   }
};

Sau khi thiết lập SipAudioCall.Listener, bạn có thể thực hiện cuộc gọi. Phương thức SipManager makeAudioCall nhận các tham số sau:

  • Cấu hình SIP cục bộ (phương thức gọi).
  • Hồ sơ SIP kết nối ngang hàng (người dùng được gọi).
  • SipAudioCall.Listener để nghe cuộc gọi sự kiện từ SipAudioCall. Đây có thể là null, nhưng như đã trình bày ở trên, trình nghe được dùng để thiết lập mọi thứ sau khi cuộc gọi được thiết lập.
  • Giá trị thời gian chờ, tính bằng giây.

Ví dụ:

Kotlin

val call: SipAudioCall? = sipManager?.makeAudioCall(
        sipProfile?.uriString,
        sipAddress,
        listener,
        30
)

Java

call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);

Đang nhận cuộc gọi

Để nhận cuộc gọi, ứng dụng SIP phải bao gồm một lớp con của BroadcastReceiver có khả năng phản hồi một ý định cho biết có cuộc gọi đến. Do đó, bạn phải thực hiện những việc sau trong ứng dụng của bạn:

  • Trong AndroidManifest.xml, hãy khai báo <receiver> Trong Sipdemo, đây là <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />.
  • Triển khai trình thu nhận, là một lớp con của BroadcastReceiver. Trong Sipdemo, đây là IncomingCallReceiver.
  • Khởi chạy hồ sơ cục bộ (SipProfile) bằng một ý định đang chờ xử lý kích hoạt dịch vụ nhận của bạn khi ai đó gọi đến hồ sơ cục bộ.
  • Thiết lập bộ lọc ý định lọc theo hành động đại diện cho cuộc gọi đến. Trong Sipdemo, thao tác này là android.SipDemo.INCOMING_CALL.

Phân loại con BroadcastReceiver

Để nhận cuộc gọi, ứng dụng SIP của bạn phải là lớp con BroadcastReceiver. Các Hệ thống Android xử lý các cuộc gọi SIP đến và truyền tin "cuộc gọi đến" call" ý định (như được ứng dụng xác định) khi ứng dụng nhận được một cuộc gọi. Đây là lớp con BroadcastReceiver mã từ mẫu SIP.

Kotlin

/**
 * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
 */
class IncomingCallReceiver : BroadcastReceiver() {

    /**
     * Processes the incoming call, answers it, and hands it over to the
     * WalkieTalkieActivity.
     * @param context The context under which the receiver is running.
     * @param intent The intent being received.
     */
    override fun onReceive(context: Context, intent: Intent) {
        val wtActivity = context as WalkieTalkieActivity

        var incomingCall: SipAudioCall? = null
        try {
            incomingCall = wtActivity.sipManager?.takeAudioCall(intent, listener)
            incomingCall?.apply {
                answerCall(30)
                startAudio()
                setSpeakerMode(true)
                if (isMuted) {
                    toggleMute()
                }
                wtActivity.call = this
                wtActivity.updateStatus(this)
            }
        } catch (e: Exception) {
            incomingCall?.close()
        }
    }

    private val listener = object : SipAudioCall.Listener() {

        override fun onRinging(call: SipAudioCall, caller: SipProfile) {
            try {
                call.answerCall(30)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

Java

/**
 * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity.
 */
public class IncomingCallReceiver extends BroadcastReceiver {
    /**
     * Processes the incoming call, answers it, and hands it over to the
     * WalkieTalkieActivity.
     * @param context The context under which the receiver is running.
     * @param intent The intent being received.
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        SipAudioCall incomingCall = null;
        try {
            SipAudioCall.Listener listener = new SipAudioCall.Listener() {
                @Override
                public void onRinging(SipAudioCall call, SipProfile caller) {
                    try {
                        call.answerCall(30);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;
            incomingCall = wtActivity.sipManager.takeAudioCall(intent, listener);
            incomingCall.answerCall(30);
            incomingCall.startAudio();
            incomingCall.setSpeakerMode(true);
            if(incomingCall.isMuted()) {
                incomingCall.toggleMute();
            }
            wtActivity.call = incomingCall;
            wtActivity.updateStatus(incomingCall);
        } catch (Exception e) {
            if (incomingCall != null) {
                incomingCall.close();
            }
        }
    }
}

Thiết lập một bộ lọc ý định để nhận cuộc gọi

Khi nhận được một cuộc gọi mới, dịch vụ SIP sẽ gửi một ý định kèm theo chuỗi hành động do ứng dụng cung cấp. Trong Sipdemo, chuỗi hành động này là android.SipDemo.INCOMING_CALL.

Đoạn mã này trích từ Sipdemo cho thấy cách đối tượng SipProfile được tạo với ý định đang chờ xử lý dựa trên chuỗi hành động android.SipDemo.INCOMING_CALL. Chiến lược phát hành đĩa đơn Đối tượng PendingIntent sẽ thực hiện thông báo truyền tin khi SipProfile nhận được một cuộc gọi:

Kotlin

val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) {
    SipManager.newInstance(this)
}

var sipProfile: SipProfile? = null
...

val intent = Intent("android.SipDemo.INCOMING_CALL")
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA)
sipManager?.open (sipProfile, pendingIntent, null)

Java

public SipManager sipManager = null;
public SipProfile sipProfile = null;
...

Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
sipManager.open(sipProfile, pendingIntent, null);

Thông báo truyền tin sẽ bị chặn bởi bộ lọc ý định, sau đó bộ lọc này sẽ kích hoạt trình nhận (IncomingCallReceiver). Bạn có thể chỉ định một ý định lọc trong tệp kê khai của ứng dụng hoặc thực hiện trong mã như trong Sipdemo phương thức onCreate() của ứng dụng mẫu trong Activity của ứng dụng:

Kotlin

class WalkieTalkieActivity : Activity(), View.OnTouchListener {
    ...
    lateinit var callReceiver: IncomingCallReceiver
    ...

    override fun onCreate(savedInstanceState: Bundle) {
        val filter = IntentFilter().apply {
            addAction("android.SipDemo.INCOMING_CALL")
        }
        callReceiver = IncomingCallReceiver()
        this.registerReceiver(callReceiver, filter)
        ...
    }
    ...
}

Java

public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
...
    public IncomingCallReceiver callReceiver;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {

       IntentFilter filter = new IntentFilter();
       filter.addAction("android.SipDemo.INCOMING_CALL");
       callReceiver = new IncomingCallReceiver();
       this.registerReceiver(callReceiver, filter);
       ...
    }
    ...
}

Kiểm thử ứng dụng SIP

Để kiểm thử ứng dụng SIP, bạn cần có:

  • Một thiết bị di động đang chạy Android 2.3 trở lên. SIP (Giao thức khởi tạo phiên) không dây, nên bạn phải thử nghiệm trên thiết bị thực tế. Bạn sẽ không kiểm thử được trên AVD.
  • Tài khoản SIP. Có nhiều nhà cung cấp SIP cung cấp tài khoản SIP.
  • Nếu bạn đang thực hiện cuộc gọi, cuộc gọi đó cũng phải thuộc một tài khoản SIP hợp lệ.

Cách kiểm thử ứng dụng SIP:

  1. Kết nối với mạng không dây (Cài đặt > Không dây và mạng) trên thiết bị của bạn &gt; Wi-Fi > Cài đặt Wi-Fi).
  2. Thiết lập thiết bị di động để kiểm thử, như mô tả trong phần Phát triển trên thiết bị.
  3. Chạy ứng dụng trên thiết bị di động của bạn, như mô tả trong phần Phát triển trên thiết bị.
  4. Nếu đang sử dụng Android Studio, bạn có thể xem kết quả của nhật ký ứng dụng bằng cách mở bảng điều khiển Nhật ký sự kiện (View > Tool Windows > Event Log (Xem > Cửa sổ công cụ > Nhật ký sự kiện).
  5. Đảm bảo ứng dụng của bạn được định cấu hình để tự động chạy Logcat khi chạy:
    1. Chọn Run > Edit Configurations (Chạy > Chỉnh sửa cấu hình).
    2. Chọn thẻ Miscellaneous (Khác) trong cửa sổ Run/Debug Configurations (Cấu hình chạy/gỡ lỗi).
    3. Trong mục Logcat, hãy chọn Show logcat tự động (Hiển thị logcat tự động) chọn OK.