[Delphi] Adaptive Icon に対応する

# 2023/12/1 追記
Delphi 12.0 Athens でアダプティブ・アイコンに対応しました！

[すべてのプラットフォームの単一アイコンと Android アダプティブ アイコン](https://docwiki.embarcadero.com/RADStudio/Athens/ja/%E6%96%B0%E6%A9%9F%E8%83%BD#.E3.81.99.E3.81.B9.E3.81.A6.E3.81.AE.E3.83.97.E3.83.A9.E3.83.83.E3.83.88.E3.83.95.E3.82.A9.E3.83.BC.E3.83.A0.E3.81.AE.E5.8D.98.E4.B8.80.E3.82.A2.E3.82.A4.E3.82.B3.E3.83.B3.E3.81.A8_Android_.E3.82.A2.E3.83.80.E3.83.97.E3.83.86.E3.82.A3.E3.83.96_.E3.82.A2.E3.82.A4.E3.82.B3.E3.83.B3)

# Adaptive Icon とは
[Adaptive Icon](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive?hl=ja) は Android 8.0 で導入された機能で、アイコンを矩形以外で表示するホームアプリでも正しくアイコンを表示出来るようにする仕組みです。

Adaptive Icon に対応していない FireMonkey のアプリを [Microsoft Launcher](https://play.google.com/store/apps/details?id=com.microsoft.launcher&hl=ja) で表示した場合、こんな風に表示されて超カッコ悪いです。
<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/0a412f53-f041-29aa-e9a3-d8894cfa8a17.png">

Adaptive Icon が設定された起動画面は↓のようにキレイに表示されます。

<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/a217534c-4ce2-1e43-5c93-2c0b20a3cf87.png">

ということで、この記事では FireMonkey 製 Android アプリで Adaptive Icon を使う**最も簡単な方法**を紹介します。

# Adaptive Icon の仕組み

### レイヤー

Adaptive Icon はアイコンを３つのレイヤーに分けたものです。

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/4a5c9305-d25e-db6e-4b7a-efdd7b7e2fe2.png">

* **マスク**
一番上の「マスク」はホームアプリが適用するものでアプリ側では何もすることはありません。
この図ではわかりやすく星形にしましたが、大抵は円形や角丸の四角形です。

* **画像(Foreground)**
開発者が用意するアイコンです。
ここでは画像と書きましたが画像以外に Path, Color などが使えます。

* **背景(Background)**
開発者が用意する背景です。
Foreground と同じように画像以外の物も使えます。

### セーフゾーン
Adaptive Icon にはセーフゾーンという概念があり、マスクで切り取られないエリアが定まっています。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/665e0535-6192-b14a-1ccd-7f17bdbf9a95.png">

中心から直径が **66dp の円形の範囲**はマスクで隠れないことが保障されています。
ですので、この範囲に収まるように画像を作ります。

### アイコンの大きさ
必ず 108dp と決まっています。
単位が dp なので、mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi で実際の大きさは変わります。
具体的には下図の様になります。

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/47f625a2-9545-910e-2b00-16438ba9353a.png">

下表は各解像度の時のアイコンの大きさとセーフゾーンを pixel 単位で表したものです。

|   dpi   | 倍率 | 実際の大きさ(px) | セーフゾーンの大きさ(px) |
|:-------:|:----:|:----------------:|:------------------------:|
|   mdpi  |    1 |       108px      |           66px           |
|   hdpi  |  1.5 |       162px      |           99px           |
|  xhdpi  |    2 |       216px      |           132px          |
|  xxhdpi |    3 |       324px      |           198px          |
| xxxhdpi |    4 |       432px      |           264px          |

# Adaptive Icon に対応する
Foreground と Background を用意して、それを Android に伝えてやれば Adaptive Icon 対応は終わりです。
しかし、どちらも用意するのは中々大変ですし、Android 7 以前 Android 8 以降に場合分けが必要だったりして非常に面倒です。

先にも述べたとおり、この記事では既存の FireMonkey アプリケーションを最小限の変更で Adaptive Icon に対応させる方法を紹介します。

### 1. ic_launcher.xml を用意する

プロジェクトフォルダなどに ic_launcher.xml というファイル名のファイルを作成し、中身を以下のように記述します。

```xml
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <background android:drawable="@android:color/black" />
    <foreground android:drawable="@drawable/ic_launcher" />
</adaptive-icon>
```

background タグで背景を指定します。ここでは純色の黒を指定しています。
他の定義済みの色も指定できます。
定義済みの色については↓こちらを参照してください。
[通信用語の基礎知識 システムカラー (Android)](https://www.wdic.org/w/TECH/%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%AB%E3%83%A9%E3%83%BC%20%28Android%29)
もちろん [colors.xml](https://developer.android.com/guide/topics/resources/more-resources#Color) に定義した色も利用可能です。

foreground タグで前景を指定します。ここではアプリのアイコンを指定しています。
↓ここで指定できる奴ですね。
<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/2c4ee620-1832-06d2-fd82-db493b628585.png">

### 2. 配置マネージャで ic_launcher.xml を追加する

配置マネージャを開いてターゲットプラットフォームを「すべての構成 - Android 64 ビット プラットフォーム」にして、左上の「追加」アイコンで ic_launcher.xml を追加します。
そして「リモートパス」に「res\mipmap-anydpi-v26\」を指定します。

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/6b25a3b9-ada0-ee26-cc6d-cdc4e8c98843.png">

### 3. AndroidManifest.template.xml を修正する

AndroidManifest.template.xml にある Application タグの icon の指定を ```@mipmap/ic_launcher``` に変更します

```xml:修正前
<application
略
  android:icon="%icon%"
略
>
```

```xml:修正後
<application
略
  android:icon="@mipmap/ic_launcher"
略
>
```

これでおしまいです。
これを実行すると…

* ホームアプリでの表示
<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/842007fc-0e02-7354-30f5-4b08daf25b40.png">

* 起動スプラッシュ

<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/d0bd8ed0-34db-3a2f-8a2e-56aa3ba882c2.png">

という形で丸くマスクされました。
ただ、これらのアイコンは大きさが 108dp ではなく、セーフエリアも完全に無視しているので画像が切れてしまっています。
Delphi の IDE では、アイコンには特定のサイズの画像しか指定できません（違うサイズを指定するとエラーになります）。
ですので、ちゃんとした AdaptiveIcon にするには foreground タグに mipmap や Path を指定する必要があります。
ここでは mipmap を使う方法を紹介します。

### 4. mipmap

mipmap は、解像度毎に最適な画像を用意する手法のことです。

Adaptive Icon では、m, h, xh, xxh, xxxh の解像度毎に用意された画像のことを指します。
この記事では FireMonkey のマークをセーフゾーンの大きさの png として用意しました。
（黒なので良くわかりませんがマーク以外の部分は透過しています）

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/6af85061-39d4-5cb0-dcb4-10e5584be12e.png">

用意した画像を配置マネージャに登録します。

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/596e4381-3786-1c68-a4f3-db7c7686eec3.png">

登録したファイルの「リモートパス」を次のように設定します。

| ローカルファイル名 |     リモートパス    |
|:------------------:|:-------------------:|
| icon_m.png         | res\mipmap-mdpi\    |
| icon_h.png         | res\mipmap-hdpi\    |
| icon_xh.png        | res\mipmap-xhdpi\   |
| icon_xxh.png       | res\mipmap-xxhdpi\  |
| icon_xxxh.png      | res\mipmap-xxxhdpi\ |

「リモート名」はすべて「ic_foreground.png」とします。

次に ic_launcher.xml の中身を次のように変更します。

```xml
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <background android:drawable="@android:color/black" />
    <foreground android:drawable="@mipmap/ic_foreground" />
</adaptive-icon>
```

foreground タグの指定を **"@mipmap/ic_foreground"** に変更しています。
@mipmap として指定すると res\mipmap-?dpi\ から最適な画像を持ってきます。

これで実行すると…

* ホームアプリでの表示
<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/cd086360-b425-ae56-eb7f-4da3678230d8.png">

* 起動スプラッシュ
<img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/a217534c-4ce2-1e43-5c93-2c0b20a3cf87.png">

となり、無事キレイに表示されました！

# まとめ
FireMonkey アプリを AdaptiveIcon に対応させるには

・mipmap 画像を作り配置マネージャに登録する
・ic_launcher.xml を作り配置マネージャに登録する
・AndroidManifest.template.xml の android:icon を変更する

という３つの手順だけです！

ただし、この方法だと Android 8 未満の [roundIcon](https://developer.android.com/about/versions/nougat/android-7.1.html#circular-icons) には対応しないので注意してください。
流石に Android 8 未満の端末は切り捨てても良いと思いますが…

また今回は mipmap を使用しましたが SVG を path タグで記述すればファイルは１つで済みます（解像度毎に用意する必要が無いので）。

IDE で標準でサポートされるべき！と思った方は↓の QP に Vote を！
https://quality.embarcadero.com/browse/RSP-21335