AndroidスマホにKDDI系SIMを入れたときに2重に表示されるキャリア表示を改善する

## はじめに
スマートフォンに通信キャリアのSIMを挿入すると、挿入したSIMのキャリア名が表示されるようになっていますが、一部のスマートフォンで一部の通信キャリアのSIMを挿入すると、キャリア名表示が二重に表示されてしまうことがあります。
特にGoogle PixelにKDDI系のSIMを入れると、auの場合は「KDDI - au」、UQ mobileの場合は「KDDI - UQ mobile」、povoの場合は「KDDI - povo」と表示され、キャリア表示が冗長的になってしまいます。

![Screenshot_20240220-110340.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/b5dd37fb-ac96-435e-cba6-392f84623b09.png)

本記事では、これをそれぞれ「au」「UQ mobile」「povo」の表示だけにする方法を解説します。

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

## なぜこのような表記になるのか
Androidのキャリア表示は、挿入しているSIMの通信キャリアと実際に接続しているキャリアの名前を取得し表示しています。
Androidでは、SIMのキャリア名と接続しているキャリア名が同じ場合は単一の表示になりますが、国際ローミング等で両者が異なっている場合は、「《接続先のキャリア》 -  《SIMのキャリア》」という表示になります。この実装は、`frameworks/opt/telephony`の[`ServiceStateTracker.java#getCarrierName()`](https://android.googlesource.com/platform/frameworks/opt/telephony/+/refs/heads/main/src/java/com/android/internal/telephony/ServiceStateTracker.java#2788)で行われています。
``` java
@NonNull
private String getCarrierName(boolean showPlmn, String plmn, boolean showSpn, String spn) {
    // PLMNは接続先のキャリア、SPNはSIMのキャリアを示す
    String carrierName = "";
    if (showPlmn) {
        carrierName = plmn;
        if (showSpn) {
            // PLMNとSPNが同一でない場合は、「《接続先のキャリア》 -  《SIMのキャリア》」という表示にする
            if (!Objects.equals(spn, plmn)) {
                String separator = mPhone.getContext().getString(
                        com.android.internal.R.string.kg_text_message_separator).toString();
                carrierName = new StringBuilder().append(carrierName).append(separator)
                        .append(spn).toString();
            }
        }
    } else if (showSpn) {
        carrierName = spn;
    }
    return carrierName;
}
```
## SIMのキャリア名はキャリア設定で上書きできる
Androidでは、SIMのキャリア名については各通信キャリアで任意の文字列に上書きできるようになっており、これは`packages/apps/CarrierConfig`で定義されています。
KDDIの場合の設定ファイルは下記のようになっています（当該部分のみ抜粋）。
### [au](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_1581_au.xml)
``` xml
<!-- キャリア名を上書きするかどうか -->
<boolean name="carrier_name_override_bool" value="true"/>

<!-- 上書きする場合の文字列 -->
<string name="carrier_name_string">au</string>
```

### [UQ mobile](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_2110_UQ-mobile.xml)
``` xml
<!-- キャリア名を上書きするかどうか -->
<boolean name="carrier_name_override_bool" value="true"/>

<!-- 上書きする場合の文字列 -->
<string name="carrier_name_string">UQ mobile</string>
```

### [povo](https://android.googlesource.com/platform/packages/apps/CarrierConfig/+/refs/heads/main/assets/carrier_config_carrierid_2514_povo.xml)
``` xml
<!-- キャリア名を上書きするかどうか -->
<boolean name="carrier_name_override_bool" value="true"/>

<!-- 上書きする場合の文字列 -->
<string name="carrier_name_string">povo</string>
```

以上のように、KDDIの場合は3パターン定義されており、それぞれキャリア名を上書きする形になっています。
キャリア名の上書きは、上述した`ServiceStateTracker.java`の`SPN`（SIMのキャリア）の部分のみに適用されるため、`PLMN`（接続先のキャリア：KDDI）と`SPN`（SIMのキャリア：au / UQ mobile / povo）が異なることになるため、「KDDI - povo」のような表示になってしまうのです。

## ローミング中以外はSIMのキャリア名のみを表示するように改善
同じ通信キャリアであるにもかかわらず、SIMのキャリア名と接続先のキャリア名が違うと2重表示になってしまうのは表示が冗長的なので、SIMと接続先が違うキャリアであるローミング中は接続先のキャリア名を、そうでない場合はSIMのキャリアのみを表示するようにしてみます。
先述した`ServiceStateTracker.java#getCarrierName()`を下記のように変更します。
``` java
@NonNull
private String getCarrierName(boolean showPlmn, String plmn, boolean showSpn, String spn) {
    String carrierName = "";
    if (showPlmn) {
        carrierName = plmn;
        if (showSpn) {
            carrierName = spn;
        }
    } else if (showSpn) {
        carrierName = spn;
    }
    return carrierName;
}
```
また、接続先のキャリア名を表示する判定条件に「ローミング中かどうか」を追加するため、`ServiceStateTracker.java#updateSpnDisplayLegacy()`に以下の条件を追加します。ローミング中かどうかは、`mSS.getRoaming()`で取得可能です。
``` java
private void updateSpnDisplayLegacy() {
    log("updateSpnDisplayLegacy+");

    String spn = null;
    String dataSpn = null;
    boolean showSpn = false;
    String plmn;
    boolean showPlmn;
// 〜〜中略〜〜
        // The value of spn/showSpn are same in different scenarios.
        //    EXTRA_SHOW_SPN = depending on IccRecords rule and radio/IMS state
        //    EXTRA_SPN = spn
        //    EXTRA_DATA_SPN = dataSpn
        spn = getServiceProviderName();
        dataSpn = spn;
        // L2977付近に!mSS.getRoaming()を追加する
        showSpn = !noService && !TextUtils.isEmpty(spn)
                && ((rule & CARRIER_NAME_DISPLAY_BITMASK_SHOW_SPN)
                == CARRIER_NAME_DISPLAY_BITMASK_SHOW_SPN) && !mSS.getRoaming();
// 〜〜中略〜〜
}
```

以上のように変更すると、通常時はSIMのキャリア名のみが表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715077/fd630689-f160-bf72-2419-11ef80f09741.png)