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_LOCATIONhoặcACCESS_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ặcPhoneStateListener(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)
}