Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách lấy thông tin dịch vụ SIM (Service State) trên Android

Giới thiệu

Bài viết hướng dẫn lấy thông tin trạng thái dịch vụ mạng di động (Service State) như: trạng thái đăng ký mạng, loại mạng (2G/3G/4G/5G), roaming, signal strength thông qua TelephonyManager.getServiceState().

Các bước thực hiện

Bước 1: Tạo project mới

Android Studio → File → New Project → Empty Activity.

Bước 2: Giao diện (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="16dp">

    <TextView
        android:id="@+id/tvServiceState"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Service State Info"
        android:textSize="16sp" />

</LinearLayout>

Bước 3: Khai báo quyền (AndroidManifest.xml)

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Android 12+ cần ACCESS_FINE_LOCATION cho một số API telephony -->

Bước 4: Code xử lý (MainActivity.kt)

package com.example.simservicestate

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.telephony.ServiceState
import android.telephony.TelephonyManager
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val REQUEST_CODE = 102
    private lateinit var telephonyManager: TelephonyManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        checkPermissions()
    }

    private fun checkPermissions() {
        val permissions = mutableListOf(Manifest.permission.READ_PHONE_STATE)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
        }

        val denied = permissions.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
        if (denied.isNotEmpty()) {
            ActivityCompat.requestPermissions(this, denied.toTypedArray(), REQUEST_CODE)
        } else {
            showServiceState()
        }
    }

    private fun showServiceState() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
            tvServiceState.text = "Chưa cấp quyền READ_PHONE_STATE"
            return
        }

        val serviceState = telephonyManager.serviceState
        val sb = StringBuilder()
        sb.appendLine("Service State Info:")
        sb.appendLine("===================")
        sb.appendLine("State: ${getStateString(serviceState.state)}")
        sb.appendLine("Voice Reg: ${getRegStateString(serviceState.voiceRegState)}")
        sb.appendLine("Data Reg: ${getRegStateString(serviceState.dataRegState)}")
        sb.appendLine("Operator: ${serviceState.operatorAlphaLong ?: serviceState.operatorNumeric}")
        sb.appendLine("Is Roaming: ${serviceState.roaming}")
        sb.appendLine("Network Type: ${getNetworkTypeString(serviceState)}")
        sb.appendLine("CSS Supported: ${serviceState.isCssSupported}")

        // Signal strength (cần quyền ACCESS_FINE_LOCATION trên Android 12+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val signalStrength = telephonyManager.signalStrength
            sb.appendLine("Signal Level: ${signalStrength?.level ?: "N/A"} (0-4)")
        }

        tvServiceState.text = sb.toString()
    }

    private fun getStateString(state: Int): String = when (state) {
        ServiceState.STATE_IN_SERVICE -> "IN_SERVICE (Có sóng)"
        ServiceState.STATE_OUT_OF_SERVICE -> "OUT_OF_SERVICE (Mất sóng)"
        ServiceState.STATE_EMERGENCY_ONLY -> "EMERGENCY_ONLY (Chỉ khẩn cấp)"
        ServiceState.STATE_POWER_OFF -> "POWER_OFF (Radio tắt)"
        else -> "UNKNOWN ($state)"
    }

    private fun getRegStateString(regState: Int): String = when (regState) {
        ServiceState.REGISTRATION_STATE_HOME -> "HOME"
        ServiceState.REGISTRATION_STATE_ROAMING -> "ROAMING"
        ServiceState.REGISTRATION_STATE_SEARCHING -> "SEARCHING"
        ServiceState.REGISTRATION_STATE_DENIED -> "DENIED"
        ServiceState.REGISTRATION_STATE_UNKNOWN -> "UNKNOWN"
        ServiceState.REGISTRATION_STATE_NOT_REGISTERED_NOT_SEARCHING -> "NOT_REGISTERED_NOT_SEARCHING"
        else -> "OTHER ($regState)"
    }

    private fun getNetworkTypeString(state: ServiceState): String {
        // Cần TelephonyManager.getNetworkType() hoặc CellInfo
        return "Xem TelephonyManager.getNetworkType()"
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE && grantResults.any { it == PackageManager.PERMISSION_GRANTED }) {
            showServiceState()
        } else {
            Toast.makeText(this, "Cần cấp quyền READ_PHONE_STATE và Location", Toast.LENGTH_SHORT).show()
        }
    }
}

Giải thích các trạng thái quan trọng

Trường Ý nghĩa
state Trạng thái tổng thể: IN_SERVICE, OUT_OF_SERVICE, EMERGENCY_ONLY, POWER_OFF
voiceRegState Trạng thái đăng ký голос: HOME, ROAMING, SEARCHING, DENIED
dataRegState Trạng thái đăng ký dữ liệu
roaming True nếu đang roaming
operatorAlphaLong Tên nhà mạng (Viettel, Vinaphone, MobiFone...)

Lưu ý quan trọng

  • Quyền Location: Từ Android 12 (API 31), đọc thông tin tế bào (CellInfo, SignalStrength) cần ACCESS_FINE_LOCATION hoặc ACCESS_COARSE_LOCATION.
  • Android 10+: Một số thông tin nhạy cảm bị hạn chế, cần quyền đặc biệt hoặc là system app.
  • Nhận thông báo thay đổi: Dùng TelephonyCallback (API 30+) hoặc PhoneStateListener (cũ) để lắng nghe thay đổi realtime.

Lắng nghe thay đổi realtime (API 30+)

val callback = object : TelephonyCallback(), TelephonyCallback.ServiceStateListener {
    override fun onServiceStateChanged(serviceState: ServiceState) {
        runOnUiThread { showServiceState() }
    }
}
telephonyManager.registerTelephonyCallback(mainExecutor, callback)

// Hủy đăng ký trong onDestroy()
override fun onDestroy() {
    super.onDestroy()
    telephonyManager.unregisterTelephonyCallback(callback)
}