본문 바로가기

모바일(Mobile)/안드로이드(Android)

[ANDROID] 휴대전화의 여러 정보를 얻는 방법 (Android PhoneStateListener, TelephonyCallback)

phoneStateListener, TelephonyCallback 이란?

스마트폰에서 네트워크 상태를 감지하는 리스너, 콜백 함수입니다.

phoneStateListener는 안드로이드 API 버전 12 이후로부터 deprecated 되었습니다.

이유를 찾아보려 했으나  잘 모르겠습니다... 혹시 찾으면 추가할 예정입니다...

그래도 API 12 레벨 이전 앱을 개발한다면 PhoneStateListener 도 사용해야할 수 도 있습니다.

 

PhoneStateListener

PhoneStateListener 를 사용할 때 중요한 클래스는TelephonyManager입니다.

이 클래스의 listen 메서드를 통해서 리스너를 동작시킬 수 있습니다.

listen 메서드의 두번째 매개변수를 통해 원하는 휴대전화 정보를 가져올 수 있습니다.

만약 여러개를 가져오고 싶다면 or 연산자로 묶으면 되는데, 사용 가능한 이벤트는 안드로이드 개발자 사이트를 참조.

https://developer.android.com/reference/android/telephony/PhoneStateListener

 

PhoneStateListener  |  Android Developers

 

developer.android.com

 

 

listen 메서드의 구조는 아래와 같습니다. 첫번째 인자로 리스너, 두번째 인자로 이벤트를 받습니다.

public void listen(PhoneStateListener listener, int events) {
    throw new RuntimeException("Stub!");
}

 

PhoneStateListener 사용전 권한설정이 필요합니다.

그래서 AndroidManifest.xml 중 아래의 코드가 추가되어야 합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="co.kr.package">

    <!-- 권한 추가 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- 스마트폰 상태 를 얻기 위한 권한설정 -->
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" /> <!-- TelephonyManager 사용을 위한 권한설정 : 네트워크 제공국가, 사업자, 전화번호 확인-->


    <application
    ...(후략)

</manifest>

 

 

PhoneStateListener의 사용 예시

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 안드로이드 12 이전 버전에서 사용하던 휴대폰 상태 정보 리스너
        // 13버전 이후로는 사용이 불가함.
       val phoneStateListener = object : PhoneStateListener() {

           // 통화 전달 상태 변경
           override fun onCallForwardingIndicatorChanged(cfi: Boolean) { TODO(); }
           // 통화 상태 변경
           override fun onCallStateChanged(state: Int, phoneNumber: String?) { TODO(); }
           // 기지국 위치 변경
           override fun onCellLocationChanged(location: CellLocation?) { TODO();}
           // 데이터 송수신 활동
           override fun onDataActivity(direction: Int) {TODO();}
           // 데이터 연결상태
           override fun onDataConnectionStateChanged(state: Int) { TODO(); }
           // 메세지 대기 상태 변경
           override fun onMessageWaitingIndicatorChanged(mwi: Boolean) { TODO(); }
           // 단말기의 서비스 상태
           override fun onServiceStateChanged(serviceState: ServiceState?) {
               val tag = "PHONE SERVICE >>>>>>>> "
               // ServiceState에 작성된 프로퍼티
               // mVoiceRegState
               // mDataRegState
               // mChannelNumber
               // duplexMode()
               // mCellBandwidths -> [] 배열의 형태

               when(serviceState?.state){
                   ServiceState.STATE_EMERGENCY_ONLY -> {Log.d(tag, "EMERGENCY")};
                   ServiceState.STATE_OUT_OF_SERVICE -> {Log.d(tag, "OOS")};
                   ServiceState.STATE_POWER_OFF -> {Log.d(tag, "POWER_OFF")}
                   ServiceState.STATE_IN_SERVICE -> { Log.d(tag, "IN_SERVICE") };
               }
           }

           // 신호 세기 변경 시
           override fun onSignalStrengthChanged(asu: Int) { TODO(); }

       }

        val manager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager;
        manager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);


    }

}

 

TelephonyCallback

안드로이드 API 버전 12 이후 phoneStateListener를 대체하는 콜백함수입니다.

 

TelephonyCallback도 사용전 권한설정이 필요합니다.

마찬가지로 AndroidManifest.xml 중 아래의 코드가 추가되어야 합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="co.kr.package">

    <!-- 권한 추가 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- 스마트폰 상태 를 얻기 위한 권한설정 -->
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" /> <!-- TelephonyManager 사용을 위한 권한설정 : 네트워크 제공국가, 사업자, 전화번호 확인-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 휴대폰 네트워크 접속 권한 -->


    <application
        ...(후략)

</manifest>

 

 

TelephonyCallback의 사용 예시

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 12버전 이후부터 , 전화 상태 감지하는 방법
        // TelephonyCallback
        // 휴대전화 정보를 얻는 방법 1.
        val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager;
        val callBackTag = "TelephonyCallback >> "
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            telephonyManager.registerTelephonyCallback(
                mainExecutor,
                object : TelephonyCallback(), TelephonyCallback.CallStateListener {
                    override fun onCallStateChanged(state: Int) {
                        when(state) {
                            TelephonyManager.CALL_STATE_IDLE -> { Log.d(callBackTag, "state : $state");} // 통화 대기 상태
                            TelephonyManager.CALL_STATE_OFFHOOK -> { Log.d(callBackTag, "state : $state");} // 통화 중인 상태
                            TelephonyManager.CALL_STATE_RINGING -> { Log.d(callBackTag, "state : $state");} // 벨이 울리는 상태
                        }
                    }
                }
            )
        }

        Log.d("NETWORK :::: ", "state : ${isNetworkAvailable()}");

        // 휴대전화 정보를 얻는 법 2
        val networkReq : NetworkRequest
            = NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .build();

        val conManager:ConnectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager;

        conManager.requestNetwork(networkReq, object:ConnectivityManager.NetworkCallback(){
            val tag = "NetworkCallback2 :::: "
            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                Log.d(tag, "네트워크 사용 가능")
            }

            override fun onUnavailable() {
                super.onUnavailable()
                Log.d(tag, "네트워크 사용 불가능")
            }
        })


    }

    // 휴대전화 정보를 얻은 후 결과를 boolean으로 리턴하는 함수
    // 여기서 코드를 편집하여 상태값 자체를 출력할 수도 있다.
    private fun isNetworkAvailable():Boolean{
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val network = connectivityManager.activeNetwork?: return false;
            val actNetwork = connectivityManager.getNetworkCapabilities(network)?:return false; // 이 값이 null 이면 현재 스마트폰이 네트워크에 접속할 수 없는 상태임을 의미
            return when {
                actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
                    Log.d("WIFI", "WIFI")
                    true;
                }
                actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)->{
                    Log.d("CELLULAR", "CELLULAR");
                    true
                }
                else -> false;
            }

        }else {
            return connectivityManager.activeNetworkInfo?.isConnected?:false;
        }

    }
}

 

 

TelephonyCallback의 프로퍼티에 대한 자세한 설명은 아래의 개발자 사이트에 나와 있습니다.

 

https://developer.android.com/reference/android/telephony/TelephonyCallback

 

TelephonyCallback  |  Android Developers

 

developer.android.com

 

휴대전화 정보를 얻는 법 1에서 사용한 TelephonyManager의 프로퍼티들은 아래의 사이트를 참조하면 됩니다.(엄청 많음)

개발하려는 어플리케이션에 따라 적당히 when 절에 분기를 추가해서 로직을 작성하면 될 것 같습니다.

 

https://developer.android.com/reference/android/telephony/TelephonyManager

 

TelephonyManager  |  Android Developers

 

developer.android.com