【android】折りたたみ式端末対応

この記事は[and factory.inc Advent Calendar 2021](https://qiita.com/advent-calendar/2021/andfactory) 21日目の記事です。
昨日は [@ticktakclock](https://qiita.com/ticktakclock) さんの [【Jetpack Compose】お気に入りボタンのタップアニメーションの作り方](https://qiita.com/ticktakclock/items/e671733d1c5daac10ac7) でした。

# はじめに
android10で折りたたみ式端末のサポートが正式に始まり、OPPOから13万円台の折りたたみスマホが発表されるなど、折りたたみ端末が身近になりつつある昨今。
GoogleDevelopers[折りたたみ式端末に対応したアプリの作成](https://developer.android.com/guide/topics/ui/foldables?hl=ja)から、どう対応していくのかを見てみます

# [序文](https://developer.android.com/guide/topics/ui/foldables?hl=ja)
> 折りたたんだり広げたりすることで、画面のサイズ、密度、または縦横比が変わる場合があります。Android 開発においてこれは新しい問題ではありません。折りたたみ式でない場合にも、すでに発生しています。

既存の端末においても、画面回転や追加画面への出力時に画面構成が変更されるため。
上記に対応していれば、大きく問題になることはなさそう。

# [アプリの続行可能性](https://developer.android.com/guide/topics/ui/foldables?hl=ja#%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E7%B6%9A%E8%A1%8C%E5%8F%AF%E8%83%BD%E6%80%A7)
> 折りたたみ式端末上で実行されるアプリは、1cliつの画面から別の画面に自動的に移行することがあります。快適なユーザー エクスペリエンスを提供するため、現在のタスクが移行後もシームレスに続行することは非常に重要です。アプリは同じ状態、同じ位置で再開しなければなりません。

`ViewModel` や `onSaveInstanceState()` を利用することで自動的に処理が可能
<img src="https://developer.android.com/images/guide/topics/ui/foldables/fold-out-app-continuity.gif?hl=ja" width=320/>

## アプリサイズを変更可能にする
- [マルチウインドウのサポート設定](https://developer.android.com/guide/topics/ui/multi-window?hl=ja)　`resizeableActivity`
    - true
     - アプリが直面するフォーム ファクタや環境が何であれ、最大限の互換性が提供される。  
設定されていなければマルチウィンドウをサポートしているものとして扱われる
    - false
     - 画面分割などが無効になる  
しかし、開発者オプションの `アクティビティをサイズ変更可能にする`　から設定を無視することが可能
- [画面サポートの制限の宣言](https://developer.android.com/guide/practices/screens-distribution?hl=ja) `maxAspectRatio`, `minAspectRatio`
    - 設定することで最大アスペクト比、最小アスペクト比を制限することが可能ではあるが、`Googleではあらゆる画面サイズおよび画面密度に適応できるようにアプリを設計することを強くおすすめ`しているので推奨されていない模様
    - 設定する際は `android:resizeableActivity false`も合わせて必要になる

# [新しい画面縦横比](https://developer.android.com/guide/topics/ui/foldables?hl=ja#%E6%96%B0%E3%81%97%E3%81%84%E7%94%BB%E9%9D%A2%E7%B8%A6%E6%A8%AA%E6%AF%94)
元々androidでは端末により画面アスペクト比がまちまちであったが、android10以降サポートされるアスペクト比がさらに拡大したため、多くの端末で検証が必要

# [マルチウィンドウ](https://developer.android.com/guide/topics/ui/foldables?hl=ja#%E3%83%9E%E3%83%AB%E3%83%81%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6)
> 過去において一部の端末では、2つのアプリを横に並べて表示することが一般的でした。技術は進み、画面上で 3つ以上のアプリを同時に実行できるようになり、さらにそれらの間でコンテンツを共有できるようにもなりました。

<img src="https://developer.android.com/images/guide/topics/ui/foldables/fold-multi-window.png?hl=ja" width=320 />
[ドラッグ＆ドロップ](https://developer.android.com/guide/topics/ui/multi-window?hl=ja#dnd)の機能も実現できるとのこと

### マルチ再開
- android 9以前
    - フォーカスのあったアプリのみ再開状態
    - それ以外は一時停止状態
- android 10以降
    - 全てのアクティビティが再開状態
    - 最前面に透過アクティビティがある場合、またはアクティビティがフォーカス可能でない場合、アクティビティが一時停止する可能性がある

## 排他的リソースアクセス
> マルチ再開機能のサポートに役立つ機能として、新しいライフサイクル callback である Activity#onTopResumedActivityChanged() があります。
このメソッドは、アクティビティが最前面の再開アクティビティ位置を獲得した時点、またはそれを失った時点で呼び出されます。これは、アクティビティでマイクやカメラなど共有単一ユーザー リソースが使用されている場合に、そのことを知るために重要です。

ファイルやカメラなど、1つのリソースに対してそれぞれのアプリから排他的にアクセスする必要がある場合がある。
この際には `onTopResumedActivityChanged` を利用することで、上記処理することが可能

# [マルチディスプレイ](https://developer.android.com/guide/topics/ui/foldables?hl=ja#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4)
android 10以上では、２次ディスプレイ上のアクティビティがサポートされている。
マルチディスプレイサポート自体は[android 8.0](https://developer.android.com/about/versions/oreo/android-8.0?hl=ja#mds)から
折りたたみ式端末のみに限った話題ではないので、一部割愛

## ディスプレイの切り欠き
- [ディスプレイカットアウトのサポートに関するベストプラクティス](https://developer.android.com/guide/topics/display-cutout?hl=ja#best_practices_for_display_cutout_support)  
切り欠きや、パンチホール（[ディスプレイカットアウト](https://developer.android.com/guide/topics/display-cutout?hl=ja)）のある端末では表示要素が切り欠きに重なってしまうことがある。  
こちらは折りたたみ式端末に限った話ではないので、参考にしたい

# [テスト](https://developer.android.com/guide/topics/ui/foldables?hl=ja#%E3%83%86%E3%82%B9%E3%83%88)
主な確認点

- 構成の変更
- マルチウィンドウおよびマルチ再開
- サイズ変更と新しい画面縦横比

AOSPエミュレータで確認可能
![スクリーンショット 2021-12-20 11.18.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324924/ae56b046-88c0-52c7-f16e-d7b9cd136257.png)
foldableだけでなく、rollableもある

# その他
- [折りたたみ式サポートが関係するandroid10の変更](https://developer.android.com/about/versions/10/behavior-changes-10?hl=ja#foldables)

# まとめ
- `ViewModel`, `onSaveInstanceState()`を利用して設定変更に耐えられるようにする
- アスペクト比の変更を考慮したレイアウト実装、テストを行う
- ディスプレイカットアウト対応
- マルチウィンドウ機能の有効活用

# 感想
基本的には従来から気をつけるべき内容ではありますが、マルチウィンドウのD&Dなど、知らなかった内容もありました。
アプリのジャンルによっては折りたたみ式端末への最適化が[PlayMediaExperience Program](https://play.google.com/console/about/mediaprogram/)の適用要件になっていたりするので、しっかり対応できるようにしていきたいですね。