Androidのアンテナピクトを5G NRに接続しているときだけ「5G」表示にする

## はじめに
5Gのサービスが始まって早4年が経とうとしています。5Gのエリアも広がり、スマートフォンのアンテナ表示にも「5G」と表示される頻度が高くなってきたように感じています。
一方、5Gはまだまだ過渡期であり、都心部を中心に通信が逼迫し、いわゆる「**パケ詰まり**」が起きている通信キャリアもあります。また、「5Gにするとバッテリー消費が激しい」とか、LTE向けに割り当てられた周波数を5Gに転用し、LTEと大して通信速度が変わらない「なんちゃって5G」という問題もあります。
そして、最大の問題点としては**5Gにつながっていないのに「5G」と表示される**という点ではないでしょうか。「5Gと表示されているのに通信し始めたら4Gになってしまった」「5Gと4Gの表示がコロコロ変わって安定しない」といった声をSNS上で見かけます。なぜこのような表示になっているのか、5Gにつながっているときだけ5Gと表示するにはどうすればいいのか、この記事で解説したいと思います。

### ⚠︎注意
この記事ではAndroidのカスタムROMに関する事柄を記載しています。ご自身のスマホにカスタムROMをインストールすることによる損害に関しては、ご自身の責任の下で行ってください。

## 現在の5Gは「真の5Gではない」
現在主流となっている5Gは「**5G NSA**」という規格です。「NSA」とは「Non standalone」の略称で、「自立していない5G」という意味になります。一方、真の5Gと呼ばれる5Gは「5G SA」（Standalone）と称し、「自立している5G」という意味になります。

### 自立していない5G
5G NSAは文字通り「自立していない」ので、誰かの助けを借りないと5Gに接続することができません。この「誰か」は「LTE（4G）基地局」になります。詳しい解説は割愛させていただきますが、5G NSAはまず一旦（5G用にカスタマイズされた）LTE基地局[^1]に接続し、その後に5G NR（5G基地局）に接続します。
この**eLTEに接続できない限り、5G NSAでは5Gに接続することができない**のです。
[^1]:eLTE = enhanced LTE、アンカーバンドとも言います

### 5G基地局は報知情報を出さない
通常電波を出す基地局は、「報知情報」というこの基地局がどこの事業者で何の基地局なのかという情報をスマートフォンに送信しています。スマートフォンはその情報を元に適切な基地局をサーチし、電波を補足することで通信・通話ができるようになります。
一方、**5G NSAの5G基地局は「報知情報」を出しません**。その代わりに、5G基地局とセットになったeLTE基地局が、「近くに5G基地局があります」という報知情報を送信し、それを頼りにスマートフォンは5Gに接続することとなります。

ざっくりとした流れとしては以下のようになります。

### 1. eLTE基地局が報知情報を送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/eadab31a-9b53-aa1e-9eaf-f82ad05b40eb.png)
まず、eLTE基地局が「近くに5G基地局があります」という報知情報をスマートフォンに送信します。

### 2. eLTE基地局に接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/d16d8cc6-d375-6dd3-26d4-5028aab237b4.png)
スマートフォンはその情報を元に、一旦eLTE基地局に接続します。

### 3. 5G基地局に接続し、通信を開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/47e15fc2-a411-1bd0-de08-d83027741751.png)
その後、eLTE基地局から送信された報知情報を元に近くにある5G基地局をサーチし、問題なければ5G基地局に接続され5Gで通信が開始されます。
近くに5G基地局がなかったり、5G基地局との接続に失敗した場合はeLTE基地局を介してそのままLTE（4G）で通信が行われます。

### 4. 通信終了後、5G基地局からは切断
5Gでの通信が終了し待機中の状態になると、スマートフォンは5G基地局から切断し、eLTE基地局のみの接続となります。

## アンテナピクトの表示はどのようになっているのか
通常、スマートフォンの「5G」「4G」「4G+」という表示は、「何の規格で通信しているか」を示すもので、「4G」であれば「4Gで通信している」という形になります。一方、5Gの場合は上述した趣旨から若干外れてしまうのです。
日本で発売されているスマートフォン（一部のキャリアフリースマートフォンを除きます）は、総務省と通信キャリアとの取り決め[^2]により、以下のような仕様になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/cd7c4c5d-3b70-6831-5430-6a5bfc667292.png)

[^2]:[既存帯域のNR化に伴うユーザー保護方策の検討について - 新世代モバイル通信システム委員会技術検討作業班資料(PDF)](https://www.soumu.go.jp/main_content/000691397.pdf)

これを、先述した5G基地局への接続フローに当てはめると、下記のようになります。

1. eLTE基地局から報知情報を受信し、eLTE基地局に接続
→ アンテナピクトは「**5G**」表示
2. 5G基地局に接続し、5Gで通信を開始
→ アンテナピクトは「**5G**」表示
3. 5G基地局に接続できず、LTEで通信を開始
→ アンテナピクトは「**4G**（あるいは**4G+**）」表示
4. 通信終了後、5G基地局から切断しeLTE基地局のみ接続
→ アンテナピクトは「**5G**」表示

ここで、1のフローに注目です。1のフローでは、あくまで**eLTEに接続**しただけで、**5Gには接続していません**。ですが、スマートフォンの表示は5Gになるのです。そして、5Gで通信できれば表示は5Gのまま、5Gに接続できず、LTE（4G）で通信した場合は表示が4Gに変化します。
接続した基地局が5G対応のeLTEであるにもかかわらず、近くに5G基地局がなかった場合は通信するたびに表示が5Gから4Gに変化することになり、結果としてSNSに上がっている「5Gと4Gの表示がコロコロ変わって安定しない」という体感になってしまうのです。

## Androidスマホの実装を見る
さて、ここからは実際にAndroidがどのような表示の実装をしているのか見ていきます。
Androidは、Android 10より5G NSAに対応しており、表示の実装に関する[公式ドキュメント](https://source.android.com/docs/core/connect/5g-nsa)が用意されています。
5G接続のシナリオとして、Androidでは下記の5つが想定されています。

1. *Device connected to 5G cell as the secondary cell and using millimeter wave.*
→ 5Gミリ波に接続
2. *Device connected to 5G cell as the secondary cell but not using millimeter wave.*
→ ミリ波以外の5G（Sub-6）に接続
3. *Device camped on a network that has 5G capability (device doesn't have to be connected to a 5G cell as a secondary cell) and the use of 5G isn't restricted and radio resource control (RRC) is in the IDLE state (no connection).*
→ eLTE基地局に接続し、通信待機中の状態（この場合は5G基地局には未接続）
4. *Device camped on a network that has 5G capability (device doesn't have to be connected to a 5G cell as a secondary cell) and the use of 5G isn't restricted and radio resource control (RRC) is in the CONNECTED state.*
→ 5G基地局に接続している状態
5. *Device camped on a network that has 5G capability (device doesn't have to be connected to a 5G cell as a secondary cell) but the use of 5G is restricted.*
→ eLTE基地局に接続しているが、スマートフォンが5G使用不可の状態

実際の設定は通信キャリアごとに設定ファイルが用意されており、各キャリアの仕様に準拠する形となっています。
日本の通信キャリアの設定を下記に一部記載してみます。
各キャリアの設定は`packages/apps/CarrierConfig`が担っており、こちらに各キャリアの設定ファイルがまとまっています。

### [NTTドコモ](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_850_NTT_DOCOMO.xml)
``` xml
<string name="5g_icon_configuration_string">connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G</string>
<string name="5g_icon_display_grace_period_string">connected_mmwave,legacy,31;connected,legacy,31;connected_mmwave,not_restricted_rrc_con,31;connected,not_restricted_rrc_con,31;not_restricted_rrc_idle,not_restricted_rrc_con,15</string>
```

### [KDDI](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_1581_au.xml)
``` xml
<string name="5g_icon_configuration_string">connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G</string>
<string name="5g_icon_display_grace_period_string">connected_mmwave,legacy,31;connected,legacy,31;connected_mmwave,not_restricted_rrc_con,31;connected,not_restricted_rrc_con,31;not_restricted_rrc_idle,not_restricted_rrc_con,15</string>
```

### [SoftBank](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_1894_SoftBank.xml)
``` xml
<string name="5g_icon_configuration_string">connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G</string>
<string name="5g_icon_display_grace_period_string">connected_mmwave,legacy,31;connected,legacy,31;connected_mmwave,not_restricted_rrc_con,31;connected,not_restricted_rrc_con,31;not_restricted_rrc_idle,not_restricted_rrc_con,15</string>
```

### [楽天モバイル](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_2429_Rakuten-Mobile-MNO.xml)
``` xml
<string name="5g_icon_configuration_string">connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G</string>
<string name="5g_icon_display_grace_period_string">connected_mmwave,legacy,15;connected,legacy,15;connected_mmwave,not_restricted_rrc_con,15;connected,not_restricted_rrc_con,15;not_restricted_rrc_idle,not_restricted_rrc_con,15</string>
```

どのキャリアもほぼ同じ設定ですが、一部楽天モバイルが違う設定になっています。
ここで`5g_icon_configuration_string`は「どのタイミングで5Gと表示するか」、`5g_icon_display_grace_period_string`は「端末のステータスが変わった際に、何秒間表示を維持するか」を示しています。
`5g_icon_configuration_string`は、上述した5つのシナリオに対応しており、それぞれ

1. `connected_mmwave`
2. `connected`
3. `not_restricted_rrc_idle`
4. `not_restricted_rrc_con`
5. `restricted`

という文字列で指定する形となっています。

``` xml
<string name="5g_icon_configuration_string">connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G</string>
```
は、「`connected_mmwave`、`connected`、`not_restricted_rrc_idle`の場合のみ5Gと表示する」という設定になっています。

そして、
``` xml
<string name="5g_icon_display_grace_period_string">connected_mmwave,legacy,31;connected,legacy,31;connected_mmwave,not_restricted_rrc_con,31;connected,not_restricted_rrc_con,31;not_restricted_rrc_idle,not_restricted_rrc_con,15</string>
```
は、ざっくり言うとステータスが変わった場合に「前の表示を31秒維持する（楽天モバイルだけ15秒）」というような内容になっています。

以上のことから、日本のキャリアの端末では、総務省の準拠通り「**5G対応のLTE基地局につながったとき、5Gで通信しているとき**」に「5G」の表示になり、「**5Gから切断された場合は切断から31秒後**（楽天モバイルは15秒後）**に4G（4G+）の表示**」になるという仕様で実装されていることが分かります

## 5G NRに接続しているときだけ「5G」表示にする
さて、いよいよここから実際のAndroidのソースコードを変更し、5G基地局（5G NR）に接続しているときだけ「5G」と表示されるようにしてみます。

### アンテナピクトの表示をコントロールしている部分はどこか
5Gの表示をコントロールしているのは、[`frameworks/opt/telephony`](https://android.googlesource.com/platform/frameworks/opt/telephony/)の[`NetworkTypeController.java`](https://android.googlesource.com/platform/frameworks/opt/telephony/+/refs/heads/main/src/java/com/android/internal/telephony/NetworkTypeController.java)が担っています。
`NetworkTypeController.java`のL353-359に下記の記載があります。
``` Java
String nrIconConfiguration = config.getString(
        CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING);
String overrideTimerRule = config.getString(
        CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING);
String overrideSecondaryTimerRule = config.getString(
        CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING);
createTimerRules(nrIconConfiguration, overrideTimerRule, overrideSecondaryTimerRule);
```
これらは、先述したキャリア設定から値を読み込んでくる部分のコードです。こちらを以下のように書き換えます。
``` Java
createTimerRules();
```

そして、`createTimerRules`の引数を空にし、下記のように書き換えます。
``` Java
private void createTimerRules() {
    Map<String, OverrideTimerRule> tempRules = new HashMap<>();
    // NR_ADVANCED(5Gミリ波)への接続が「CONNECTED」の場合のみ「5Gミリ波」と表示する
    tempRules.put(STATE_CONNECTED_NR_ADVANCED, new OverrideTimerRule(STATE_CONNECTED_NR_ADVANCED, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED));
    // 5Gへの接続が「CONNECTED」の場合のみ「5G」と表示する
    tempRules.put(STATE_CONNECTED, new OverrideTimerRule(STATE_CONNECTED, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA));

    // Ensure all states have an associated OverrideTimerRule and icon
    for (String state : ALL_STATES) {
        if (!tempRules.containsKey(state)) {
            tempRules.put(state, new OverrideTimerRule(
                    state, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE));
        }
    }

    mOverrideTimerRules = tempRules;
    if (DBG) log("mOverrideTimerRules: " + mOverrideTimerRules);
}
```
この`createTimerRules()`が実際に設定ファイルを読み込んで5Gの表示をコントロールしているメソッドになります。
``` Java
tempRules.put(STATE_CONNECTED, new OverrideTimerRule(STATE_CONNECTED, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA));
```
の部分で、`STATE_CONNECTED`、すなわち5つのシナリオのうち「2」`connected`の場合のみ`TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA`（表示を5Gにする）にすることで、実際に5G NR（5G基地局）に接続している場合のみ「5G」と表示させることが可能です。

### ソースコードを編集し、ビルド
カスタムROMの作り方については本記事では割愛します。ソースコードのダウンロード、ビルドは[こちらの記事](https://qiita.com/aoi-stella/items/2707663103d937bf4473)に詳しく書かれていますので参考にしてください。

## メリット
* 本当に5G基地局に接続しているときだけ「5G」表示になるので、電測アプリで確認しなくて済む

## デメリット
* 5Gエリアに居ても5Gに接続しない限り5G表示にならないので、どこで5Gが掴めるのか分からない
* 4Gと5Gの表示が高頻度でコロコロ変わる
* 待機中は4Gの表示になるので、5Gエリアなのか分からない

## 結論
ちゃんと5G接続時のみ5G表示になってほしい人におすすめ。

## 参考文献
* IIJmio meeting 27 5G NSAについて
https://www.slideshare.net/IIJ_techlog/iijmio-meeting-27-5g-nsa-234101136
* MVNOも導入予定の5G　その際に悩ましい「5Gピクト」「端末」「エリア」問題 - ITmedia mobile
https://www.itmedia.co.jp/mobile/articles/2005/28/news117.html
* AWS EC2使ってAndroidOSビルドしてみた！ - @aoi-stella 
https://qiita.com/aoi-stella/items/2707663103d937bf4473