Android 9・10でBroadcastReceiverを使った着信番号取得がうまくいかない時のメモ

BroadcastReceiverを使った着信番号の取得が、なかなかうまくいかなかったので解決方法を書いておきます。

# :checkered_flag: やりたいこと
電話がかかってきたときに、かかってきた番号を取得したい。

# :pencil2: 電話の状態を取得するReceiver
まず、検索してよく書いてあったコードで試しました。

```xml:Android.Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.callreceivetest">

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>
```

※TextViewは電話番号を表示するため

```java:MainActivity.java
    TextView callinfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        callinfo=findViewById(R.id.callinfo);

        //リスナー設定
        TelephonyManager telephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
        telephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);

    }

    PhoneStateListener mListener = new PhoneStateListener(){
        @Override
        public void onCallStateChanged(int state, String callNumber) {
            //Log.d(TAG, ":" + state+"-PhoneNumber:"+callNumber);
            switch(state){
                case TelephonyManager.CALL_STATE_IDLE:      //待ち受け（終了時）
                    Toast.makeText(MainActivity.this, "通話終了\nCALL_STATE_IDLE", Toast.LENGTH_SHORT).show();
                    break;
                case TelephonyManager.CALL_STATE_RINGING:   //着信*
                    if(callNumber==null){
                        callNumber="";
                    }
                    Toast.makeText(MainActivity.this, "着信中\nCALL_STATE_RINGING: " + callNumber, Toast.LENGTH_SHORT).show();
                    callinfo.setText("着信："+callNumber);
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:   //通話
                    Toast.makeText(MainActivity.this, "通話中\nCALL_STATE_OFFHOOK", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
```

このコードをAndroid 10のエミュレーターで実行したところ、画像のようになって電話の状態は取得できているものの、電話番号がなぜか取得できません。
![000035.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/37c32055-da8d-0e3d-1aff-a9ab2f766094.png)

# :bulb: 電話番号が取得できない原因
Android9・10（APIレベル28以上）から、BroadcastReceiverを使って電話番号を取得する際に必要な権限が変更になったようです。
参考サイト：https://developer.android.com/about/versions/pie/android-9.0-changes-all?hl=ja#restrict-access-phone-numbers
今回はonCallStateChanged()を使って取得するので、READ_PHONE_STATE（電話）に加えて**READ_CALL_LOG（通話履歴）の権限が必要**です。

ただ、Android Developersのサイトには「READ_PHONE_STATE パーミッションは必要ありません。」と書かれていますが、READ_PHONE_STATEがないとAndroid9以前のバージョンでは電話番号を取得できませんでした。（実際にエミュレーターで確認しました）
なので、**全バージョンに対応させるには、READ_PHONE_STATEとREAD_CALL_LOGの２つの権限が必要**です。

#### 修正後

```xml:Android.Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.callreceivetest">

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>
```

# :iphone: 「通話履歴」権限に変更した結果
Android10でも、ちゃんと電話番号を取得することができました！
![000033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/a2c45603-0ea5-e738-e306-257ae5b86293.png)

# :chains: 参考サイト
プログラム：https://storyboard.jp/blog/android_telmanager/

着信・通話中・通話終了以外の状態を取得したいときは、ここを参考にすると分かりやすいです。
https://qiita.com/syukai/items/d4911590a001d401a028