複数のアプリの再開

Android 9 以下では、次の場合、アプリは PAUSED 状態になりました。

  • アプリの上で新しい半透明のアクティビティが起動したが、アプリが引き続き表示されている(つまり停止されなかった)場合。
  • アクティビティがフォーカスを失ったが表示が不鮮明にされず、ユーザーが操作できる場合。たとえば、マルチウィンドウ モードでは、同時に複数のアクティビティを表示してタッチ入力を受け取れます。

このような状況では、必要な一時停止の長さがアプリごとに異なりますが、アプリレベルでは違いを区別できません。

Android 10 では、表示されるスタック内の最上部のフォーカス可能なアクティビティは、すべて RESUMED 状態になります。これにより、onStop() ではなく onPause() を使用して UI の更新とユーザーとのやり取りを停止するアプリでは、マルチウィンドウ モードと MD モードの互換性が向上します。たとえば、次のようになります。

  • 分割画面の両方のアクティビティが再開される。
  • フリーフォーム ウィンドウ モードで最上部に表示されたすべてのアクティビティが再開される。
  • 複数の画面のアクティビティを同時に再開することができる。

図 1. 折りたたみ式デバイスでの複数のアプリの再開

図 2. デスクトップ モードでの複数のアプリの再開

アクティビティは、次のようにフォーカス不可能になるか部分的に遮られるかすると、PAUSED 状態になる可能性があります。

  • 最小化された分割画面(ランチャーが側面にある)で、フォーカス不可能なため最上部のアクティビティが再開されない。
  • ピクチャー イン ピクチャー モードで、フォーカス不可能なためアクティビティが再開されない。
  • アクティビティが同じスタック内の他の透明なアクティビティで覆われている。

このアプローチでは、RESUMED 状態でのみアクティビティに対するユーザー入力が有効なことをアプリに示します。Android 10 より前は、PAUSED 状態でもアクティビティに対する入力が可能でした(たとえば、Android 9 を搭載したデバイスで、分割画面の両方のアクティビティを同時に操作してみてください)。

以前の Android リリースの再開シグナルを保持し、アプリが排他的アクセスまたはシングルトン リソースへのアクセス権を取得する際に通信するために、Android 10 には新しいコールバックが含まれています。

Activity#onTopResumedActivityChanged(boolean onTop)

このコールバックは Activity#onResume()Activity#onPause() の間に呼び出されます。このコールバックは任意であり、省略することもできるため、アクティビティはシステムの最上位に配置されることなく、RESUMED から PAUSED 状態に移行する場合があります。たとえば、マルチウィンドウ モードがこれに該当します。このコールバックは省略可能なため、アクティビティのライフサイクルには含まれず、ほとんど使用されません。

最上位で再開されるアクティビティは、最上位で再開される次のアクティビティが onTopResumedActivity(true) を受け取る前に onTopResumedActivity(false) を受け取って実行を終了します。ただし、前のアクティビティがメソッド呼び出しの処理に時間がかかって、500 ミリ秒のタイムアウトに達した場合を除きます。

互換性

複数のアプリの再開を実装する際は、互換性を維持するために、次の解決策を検討してください。

1 つのアプリプロセスにおける複数のアクティビティの再開

  • 問題: Android 9 以前では、一度に再開されるのはシステム内の 1 つのアクティビティのみです。アクティビティの切り替えでは、必ずアクティビティが一時停止されてから別のアクティビティが再開されます。一部のアプリとフレームワーク(Flutter、Android の LocalActivityManager など)は、この事実を利用して、再開されたアクティビティの状態をシングルトンに保存します。
  • 解決策: Android 9 以前では、同じプロセスの 2 つのアクティビティが再開される場合、システムは Z オーダーが高いアクティビティのみを再開します。Android 10 をターゲットとするアプリでは、複数のアクティビティを同時に再開できます。

カメラへの同時アクセス

  • 問題: 次の問題は、Android 9 以前でも発生しています。たとえば、全画面で再開されたアクティビティは、ピクチャー イン ピクチャー モードの最上部にある一時停止されたアクティビティにカメラのフォーカスを合わせられませんが、マルチウィンドウ モードとマルチディスプレイ モードを広く採用することで露出が増えます。
    • RESUME 状態に対して加えられた変更が原因で、再開してもアプリとカメラの接続が解除される可能性があります。この問題に対処するには、アプリがクラッシュせずにカメラの接続解除を処理する必要があります。接続が解除されると、アプリのコールバックが切断され、API へのすべての呼び出しで CameraAccessException がスローされるようになります。
    • カメラを使用する別のアプリを他のディスプレイで開くことができるため、resizeableActivity=false はカメラへの排他的アクセスを保証しません。
  • 解決策: デベロッパーは、アプリとカメラの接続が解除されたときのロジックを組み込む必要があります。アプリがカメラから切断された場合は、カメラの可用性のコールバックを監視し、カメラへの再接続を試行して使用を続ける必要があります。Android 10 では、既存の CameraManager#AvailabilityCallback#onCameraAvailable() コールバックに加えて、再開された複数のアクティビティ間でフォーカス(およびカメラの優先度)を切り替えるケースに対応した CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged() が追加されました。アプリ デベロッパーは両方のコールバックを使用して、カメラにアクセスする最適なタイミングを判断する必要があります。

複数のアプリの再開

Android 10 では、アクティビティのライフサイクルの状態は可視性と Z オーダーによって決まります。アクティビティで可視性が更新された後の正しい状態を確認し、適用可能なライフサイクル状態を評価するには、さまざまな場所から ActivityRecord#makeActiveIfNeeded() メソッドを呼び出します。Android 10 において「アクティブ」は RESUMED または PAUSED を示し、これらの 2 つのインスタンスでのみ動作します。

Android 10 では、アクティビティの再開はシステム内の 1 つの場所ではなく、各スタックで個別にトラッキングされます。これは、マルチウィンドウ モードで複数のアクティビティ遷移を同時に実行できるためです。詳細については、ActivityStack#mInResumeTopActivity をご覧ください。

最上位で再開されたアクティビティのコールバック

最上位のアクティビティの変更(アクティビティの起動、再開、Z オーダーの変更など)につながる可能性があるアクションを行うと、ActivityStackSupervisor#updateTopResumedActivityIfNeeded() が呼び出されます。このメソッドは、最上位で再開されたアクティビティが変更されたかどうかを確認し、必要に応じて更新します。先に最上位で再開されたアクティビティが最上位での再開状態を解除していない場合は、top-resumed-state-loss メッセージが送信され、サーバー側でタイムアウトがスケジュールされます(ActivityStackSupervisor#scheduleTopResumedStateLossTimeout())。前のアクティビティで状態が解除されるか、タイムアウトが発生すると、最上位での再開状態のレポートが次のアクティビティに送信されます(以下の使用例を参照)。

ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()

最上位での再開状態の変更をクライアントにレポートする新しい TopResumedActivityChangeItem トランザクション項目が追加され、Android 9 の ActivityLifecycler アーキテクチャが利用されます。

最上位での再開状態はクライアント側に保存され、アクティビティが RESUMED または PAUSED に遷移するたびに、onTopResumedActivityChanged() コールバックを呼び出す必要があるかどうかが確認されます。これにより、サーバー側とクライアント側の間で行われるライフサイクル状態と最上位で再開された状態の通信で、特定の関連付け解除が可能になります。