참조
깡쌤의 안드로이드 프로그래밍
안드로이드 developer - TelephonyManager
안드로이드 developer - PhoneStateListener
안드로이드 developer - ConnectivityManager
틀린 부분을 댓글로 남겨주시면 수정하겠습니다!!
TelephonyManager는 전화기의 각종 정보 및 각종 상태 변경 상황을 확인할 수 있습니다.
이 클래스를 사용해 여러 정보를 획득할 수 있는데 우선 스마스폰의 상태 변경을 감지하기 위해서는 PhoneStateListener를 사용해야 합니다.
TelephonyManager를 이용해 스마트폰의 상태 변경을 감지하기 위해서는 PhoneStateListener를 구현한 클래스를 TelephonyManager에 등록해야 합니다. 등록된 PhoneStateListene의 메서드를 다양한 상태가 변경되는 상황에서 TelephonyManager가 자동으로 호출해줍니다. 예시를 통해 알아보겠습니다.
// 휴대전화의 여러 상태를 받기 위한 PhoneStateListener
val phoneStateListener = object: PhoneStateListener() {
// 서비스 상태 변경
override fun onServiceStateChanged(serviceState: ServiceState?) {
when(serviceState?.state) {
ServiceState.STATE_EMERGENCY_ONLY ->
listDatas.add("onServiceStateChanged STATE_EMERGENCY_ONLY")
ServiceState.STATE_IN_SERVICE ->
listDatas.add("onServiceStateChanged STATE_IN_SERVICE")
ServiceState.STATE_OUT_OF_SERVICE ->
listDatas.add("onServiceStateChanged STATE_OUT_OF_SERVICE")
ServiceState.STATE_POWER_OFF ->
listDatas.add("onServiceStateChanged STATE_POWER_OFF")
}
listAdapter.notifyDataSetChanged()
}
// 통화 상태 변경
override fun onCallStateChanged(state: Int, phoneNumber: String?) {
when(state) {
TelephonyManager.CALL_STATE_IDLE ->
listDatas.add("onCallStateChanged CALL_STATE_IDLE : $phoneNumber")
TelephonyManager.CALL_STATE_RINGING ->
listDatas.add("onCallStateChanged CALL_STATE_RINGING : $phoneNumber")
TelephonyManager.CALL_STATE_OFFHOOK ->
listDatas.add("onCallStateChanged CALL_STATE_OFFHOOK : $phoneNumber")
}
listAdapter.notifyDataSetChanged()
}
}
우선 PhoneStateListener를 상속하는 클래스를 생성해주면 됩니다. PhoneStateListener는 인터페이스가 아니고 클래스이므로 필요한 함수만 오버라이드하여 작성하면 됩니다. 위의 예시에서는 서비스의 상태 변경을 감지하기 위해 onServiceStateChanged 메서드와 통화 상태의 변경을 감지하기 위해 onCallStateChanged 메서드를 오버라이드하였습니다.
PhoneStateListener의 메서드들은 다음과 같습니다.
PhoneStateListener를 상속받아 만든 클래스를 TelephonyManager의 listen 메서드를 사용하여 등록하면 상태 변경을 감지합니다. 첫 번째 매개변수는 PhoneStateListener를 상속받은 클래스를, 두 번째 매개변수는 감지하려는 상태변화의 상수를 등록하면 됩니다.
// TelephonyManager 객체 생성
val telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager
// listen 메서드의 첫 번째 매개변수로 phoneStateListener를 구현한 클래스를 등록
// 뒤의 매개변수는 어느 상태변화를 감지할 것인지
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE or PhoneStateListener.LISTEN_SERVICE_STATE)
위의 예시에서는 LISTEN_CALL_STATE와 LISTEN_SERVICE_STATE를 등록하여 통화 상태 변경과 전화 상태 변경을 감지하도록 상수를 등록하여서 해당 상태가 변경되면 오버라이드하여 작성한 메서드가 호출됩니다. 상수는 아래와 같습니다.
참조
PhoneStateListener는 Api Level 31부터 deprecated되었고 TelephonyCallback 사용하라고 공식 사이트에 나와있습니다.
TelephonyManager의 메서드들을 활용하여 전화기로서의 각종 정보를 획득할 수 있습니다.
// TelephonyManager를 이용하여 스마트폰 정보 획득
listDatas.add("countryIso : ${telephonyManager.networkCountryIso}")
listDatas.add("operatorName : ${telephonyManager.networkOperatorName}")
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
listDatas.add("PhoneNumber : ${telephonyManager.line1Number}")
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 100)
}
여러 메서드가 존재하는데 telephonyManager의 getter를 사용하여 획득하면 됩니다.
네트워크 접속 정보를 확인하기 위해 사용하는 클래스입니다. 접속되어 있다면 이동통신사 망에 접속되었는지, 와이파이 망에 접속되었는지 알 수 있고 또한 네트워크 연결 상태의 변화를 알 수 있습니다.
네트워크 상태 정보를 획득하는 방법은 requestNetwork() 메서드를 이용하거나 registerNetworkCallback() 메서드를 이용하는 방법이 있습니다. requestNetwork()는 필요한 순간 한 번 정보를 획득하고, registerNetworkCallback()은 지속적으로 정보를 획득합니다.
우선 requestNetwork를 사용하기 위해 퍼미션을 추가해야 합니다.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
requestNetwork()나 registerNetworkCallback()의 기본적인 이용 방법은 NetworkRequest에 addCapability()와 addTransportType() 메서드를 이용해 획득하고자 하는 네트워크의 정보를 설정하고, 결과는 콜백 메서드를 통해 받습니다.
// 네트워크 정보를 설정하는 NetworkRequest 객체
val networkReq = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
위의 예제에서는 addCapability() 메서드의 매개변수로 NET_CAPABILITY_INTERNET을 설정하여 일반적인 데이터 통신을 위한 기능을 지정하였고 addTransportType()으로 TRANSPORT_WIFI와 TRANSPORT_CELLULAR를 지정하여 네트워크 타입으로 와이파이와 이동통신망을 지정하였습니다. 이렇게 되면 해당 요구사항에 맞는 활성화된 네트워크를 나타냅니다.
이제 준비한 NetworkRequest 객체를 requestNetwork() 혹은 registerNetworkCallback() 메서드에 NetworkCallback 객체와 같이 매개변수로 지정하면 됩니다. NetworkCallback의 콜백 메서드가 자동으로 호출되면서 네트워크 정보가 전달되는데 이를 사용하며 네트워크의 정보를 파악하면 됩니다.
// registerNetworkCallback을 사용하여 네트워크가 사용 가능하거나 불가능할 때마다 콜백 메서드 호출
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 매개변수로 NetworkRequest, NetworkCallback 객체
connectivityManager?.registerNetworkCallback(networkReq,
object : ConnectivityManager.NetworkCallback() {
// 네트워크가 연결상태 일 때 호출되는 콜백 메서드
override fun onAvailable(network: Network) {
// 활성화된 네트워크의 기능
val capabilities = connectivityManager?.getNetworkCapabilities(network)
if(capabilities != null) {
// Wifi 네트워크인 경우
if(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "NetworkInfo : Online - WIFI")
// 이동통신망 네트워크 인 경우
} else if(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.d(TAG, "NetworkInfo : Online - CELLULAR")
}
}
}
// 네트워크가 발견되지 않았을 시 호출되는 콜백메서드
override fun onUnavailable() {
Log.d(TAG, "NetworkInfo : onUnavailable")
}
// 네우워크가 끊겼을 경우 호출되거나 이 request를 더이상 만족하지 못하는 경우 호출되는 콜백메서드
override fun onLost(network: Network) {
Log.d(TAG, "NetworkInfo : onLost")
}
})
}
와이파이에 대한 접속 상태를 파악하기 위해 WifiManager 클래스를 제공합니다. 이를 이용하면 현재 스마트폰이 와이파이에 접속되었는지를 판단할 수 있습니다.
우선 WifiManager를 사용하기 위해서 퍼미션을 추가해야 합니다.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
val wifiManager = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
// 현재 wifi가 enable이 아니라면
if(!wifiManager.isWifiEnabled) {
listDatas.add("WifiManager : wifi disabled")
} else { // wifi가 enable이라면
listDatas.add("WifiManager : wifi enabled")
}
WifiManager의 isWifiEnabled() 메서드를 호출하여 현재 스마트폰의 와이파이 사용이 가능한지 불가능한지를 파악할 수 있습니다. 이는 필요할 때 한번 와이파이에 대한 접속 상태를 파악하는 방법입니다.
만약 와이파이 상태가 변할 때 이벤트 모델로 앱의 코드가 실행되어야 한다면 브로드캐스트 리시버를 이용하면 됩니다. 브로드캐스트 리시버를 이용하여 와이파이 상태를 감지하는 Action 문자열은 아래와 같습니다.
// 와이파이의 상태를 파악하는 브로드캐스트 리시버
val wifiReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// 와이파이 상태 변경 시
if(intent?.action == WifiManager.WIFI_STATE_CHANGED_ACTION) {
// 상태획득
val state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1)
// 가능 상태라면
if(state == WifiManager.WIFI_STATE_ENABLED) {
listDatas.add("WIFI_STATE_CHANGED_ACTION : enable")
} else { // 불가능 상태라면
listDatas.add("WIFI_STATE_CHANGED_ACTION : disable")
}
}
}
}
// IntentFilter 생성
val wifiIntentFilter = IntentFilter()
// action설정
wifiIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
// 동적으로 Receiver 등록
registerReceiver(wifiReceiver, wifiIntentFilter)
위의 코드는 와이파이의 상태를 파악하기 위한 코드입니다. BroadcastReceiver를 구현하는 클래스를 생성하며 그 안에서는 intent.getAction을 분기합니다.
그리고 intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1) 구문으로 와이파이 상태 값을 구하며 이렇게 얻은 state 값이 WifiManager.WIFI_STATE_ENABLED이면 와이파이는 Enable로 변경된 것입니다. 이제 이 클래스를 IntentFilter와 함께 registerReceiver에 등록하면 됩니다.