動作の変更点: すべてのアプリ

Android 12 プラットフォームには、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、targetSdkVersion に関係なく、Android 12 上で稼働するすべてのアプリに適用されます。該当する場合は、アプリをテストし、必要に応じて修正して、適切に対応してください。

Android 12 をターゲットとするアプリにのみ影響する動作変更のリストも必ずご確認ください。

ユーザー エクスペリエンス

ストレッチ オーバースクロール効果

Android 12 以降を搭載したデバイスでは、オーバースクロール イベントの視覚的な動作が変更されます。

Android 11 以前では、オーバースクロール イベントによって視覚要素にグローが表示されます。Android 12 以降の場合、ドラッグ イベントでは視覚要素がストレッチして元に戻り、フリング イベントではフリングして元に戻ります。

詳しくは、スクロール操作のアニメーション化に関するガイドをご覧ください。

アプリのスプラッシュ画面

Android 11 以前でカスタム スプラッシュ画面を実装している場合は、それが Android 12 以降でも適切に表示されるよう、アプリを SplashScreen API に移行する必要があります。アプリを移行しない場合、アプリの起動時にエクスペリエンスの低下や予期しないエクスペリエンスが生じる可能性があります。

手順については、既存のスプラッシュ画面の実装を Android 12 以降に移行するをご覧ください。

また、Android 12 以降では、新しい Android システムのデフォルトのスプラッシュ画面が、すべてのアプリのコールド スタートおよびウォーム スタートに常に適用されます。システムのデフォルトのスプラッシュ画面は、デフォルトでは、アプリのランチャー アイコン要素とテーマの windowBackground(単色の場合)を使用して作成されます。

詳しくは、スプラッシュ画面デベロッパー ガイドをご覧ください。

ウェブ インテントの解決

Android 12(API レベル 31)以降、一般的なウェブ インテントは、そのウェブ インテントに含まれる特定のドメインについてアプリが承認されている場合のみ、アプリのアクティビティに解決されます。アプリがそのドメインに対して承認されていない場合、ウェブ インテントは代わりにユーザーのデフォルトのブラウザアプリに解決されます。

アプリの承認は、次のいずれかの方法で行います。

アプリがウェブ インテントを呼び出す場合は、ユーザーにアクションの確認を求めるプロンプトまたはダイアログを追加することをご検討ください。

ジェスチャー ナビゲーションの没入モードの改善

Android 12 では既存の動作が統合され、ユーザーが没入モード時にジェスチャー ナビゲーション コマンドを実行しやすくなりました。さらに、Android 12 ではスティッキー没入モードの下位互換性が確保されています。

Display#getRealSize と getRealMetrics: 非推奨と制約

Android デバイスには、大画面、タブレット、折りたたみ式など、さまざまなフォーム ファクタがあります。各デバイスでコンテンツを適切にレンダリングするには、アプリで画面またはディスプレイのサイズを判断する必要があります。Android では、この情報を取得するためのさまざまな API が提供されてきました。Android 11 では WindowMetrics API が導入され、以下のメソッドが非推奨となりました。

Android 12 では引き続き WindowMetrics の使用を推奨し、以下のメソッドが非推奨となっています。

Display API を使用してアプリの境界を取得する動作を軽減するために、Android 12 は、完全にサイズ変更可能ではないアプリに対して API から返される値を制限します。これにより、MediaProjection でこの情報を使用しているアプリに影響が出る可能性があります。

アプリは、WindowMetrics API を使用してウィンドウの境界をクエリし、Configuration.densityDpi を使用して現在の密度をクエリする必要があります。

旧バージョンの Android との互換性を高めるために、Android 4.0(API レベル 14)以降をサポートする WindowMetrics クラスが含まれる、Jetpack WindowManager ライブラリを使用できます。

WindowMetrics の使用方法の例

まず、アプリのアクティビティが完全にサイズ変更可能であることを確認します。

アクティビティは、UI 関連の処理(特に WindowManager.getCurrentWindowMetrics() や Jetpack の WindowMetricsCalculator.computeCurrentWindowMetrics())では、アクティビティ コンテキストの WindowMetrics に依存する必要があります。

アプリで MediaProjection を作成する場合は、プロジェクター アプリが実行されているディスプレイ パーティションをプロジェクションがキャプチャするため、境界を正しいサイズにする必要があります。

アプリが完全にサイズ変更可能な場合、アクティビティ コンテキストは次のように正しい境界を返します。

Kotlin

val projectionMetrics: WindowMetrics = activityContext
      .getSystemService(WindowManager::class.java).maximumWindowMetrics

Java

WindowMetrics projectionMetrics = activityContext
      .getSystemService(WindowManager.class).getMaximumWindowMetrics();

アプリが完全にサイズ変更可能ではない場合は、WindowContext インスタンスからクエリを実行し、WindowManager.getMaximumWindowMetrics() または Jetpack メソッド WindowMetricsCalculator.computeMaximumWindowMetrics() を使用して、アクティビティの境界の WindowMetrics を取得する必要があります。

Kotlin

val windowContext = context.createWindowContext(mContext.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(mContext.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

マルチウィンドウ モードのすべてのアプリ

Android 12 では、マルチウィンドウ モードが標準の動作です。

画面が大きい(画面幅 600 dp 以上)場合は、アプリの設定にかかわらず、すべてのアプリでマルチウィンドウ モードがサポートされます。resizeableActivity="false" でディスプレイ ディメンションに合わせるために必要な場合は、アプリが互換性モードになります。

画面が小さい(画面幅 600 dp 未満)場合は、システムによりアクティビティの minWidthminHeight がチェックされ、マルチウィンドウ モードで実行可能かどうかが判断されます。resizeableActivity="false" の場合は、幅と高さの最小値にかかわらず、アプリはマルチウィンドウ モードで実行されません。

詳しくは、マルチウィンドウのサポートをご覧ください。

大画面でのカメラ プレビュー

一般にカメラアプリでは、デバイスの向きとカメラ プレビューのアスペクト比の間に一定の関係があることが想定されています。しかし、折りたたみ式デバイスなどの大画面フォーム ファクタや、マルチウィンドウやマルチディスプレイなどの表示モードには、その前提が当てはまりません。

Android 12 では、特定の画面の向きを要求する、サイズ変更できないカメラアプリ(resizeableActivity="false")は自動的にインセットの縦向きモードになり、カメラ プレビューの適切な向きとアスペクト比が維持されます。カメラの Hardware Abstraction Layer(HAL)を備えた折りたたみ式デバイスやその他のデバイスでは、カメラセンサーの方向を補正するために、カメラ出力に追加の回転が適用されます。アプリのカメラ プレビューのアスペクト比に合わせて出力がトリミングされます。トリミングと追加の回転によって、デバイスの向きやデバイスの折りたたみ / 展開状態に関係なく、カメラ プレビューが適切に表示されます。

フォアグラウンド サービス通知の UX の遅延

短時間実行されるフォアグラウンド サービスのエクスペリエンスを簡素化するため、Android 12 以降を実行するデバイスでは、特定のフォアグラウンド サービスについて、フォアグラウンド サービス通知の表示を 10 秒間遅らせることができます(少数の例外があります)。この変更により、通知が表示される前に存続時間の短いタスクを完了する機会が与えられます。

パフォーマンス

アプリ スタンバイ バケットの制限

Android 11(API レベル 30)では、アプリ スタンバイ バケットとして制限付きバケットが導入されました。Android 12 以降、このバケットはデフォルトでアクティブになっています。 制限付きバケットは、すべてのバケットの中で、優先度が最も低い(かつ制限が最も多い)バケットです。バケットを優先度の高いものから低いものの順に示すと次のようになります。

  1. アクティブ(active): 現在使用されている、またはごく最近使用されたアプリ
  2. ワーキング セット(working set): 定期的に使用されているアプリ
  3. 高頻度(frequent): 毎日ではないが、よく使用されるアプリ
  4. 低頻度(rare): あまり使用されないアプリ
  5. 制限あり(restricted): アプリがシステム リソースを大量に消費するか、望ましくない動作を引き起こす可能性がある

システムは、使用パターンだけでなくアプリの動作も考慮して、アプリを制限付きバケットに配置するかどうかを判断します。

アプリがシステム リソースを厳重に使用するのであれば、制限付きバケットに配置される可能性は低くなります。また、ユーザーがアプリを直接操作する場合、アプリは制限の少ないバケットに配置されます。

アプリが制限付きバケットに配置されているかどうかを確認する

アプリが制限付きバケットに配置されているかどうかを確認するには、getAppStandbyBucket() を呼び出します。このメソッドの戻り値が STANDBY_BUCKET_RESTRICTED の場合、アプリは制限付きバケットに配置されています。

制限付きバケットの動作をテストする

アプリが制限付きバケットに配置されたときの動作をテストする場合は、アプリをそのバケットに手動で移動できます。そのためには、ターミナル ウィンドウで次のコマンドを実行します。

adb shell am set-standby-bucket PACKAGE_NAME restricted

セキュリティとプライバシー

おおよその現在地

ダイアログでは 2 つのオプション セットが上下に表示されています
図 1. ユーザーがおおよその位置情報の提供を許可できるシステム権限ダイアログ

Android 12 以上を搭載したデバイスの場合、ユーザーはアプリがおおよその位置情報のみにアクセスするようリクエストできます。

アプリで ACCESS_FINE_LOCATION 実行時権限をリクエストする場合は、ACCESS_COARSE_LOCATION 権限もリクエストして、ユーザーがアプリにおおよその位置情報へのアクセスを許可する場合にも対応する必要があります。両方の権限を 1 つの実行時リクエストに含める必要があります。

図 1 に示すように、システム権限ダイアログには以下のオプションがあります。

  • Precise: 正確な位置情報の取得を許可します。
  • Approximate: おおよその位置情報の取得のみを許可します。

マイクとカメラの切り替え

Android 12 以降を搭載するサポート対象デバイスでは、切り替えオプションを 1 回押すだけで、デバイス上のすべてのアプリに対するカメラとマイクへのアクセスを有効または無効にできます。ユーザーは図 1 に示すように、クイック設定から、またはシステム設定の [プライバシー] 画面から、切り替えオプションにアクセスできます。

これらの切り替えについて、またアプリが CAMERA および RECORD_AUDIO 権限に関するベスト プラクティスに沿っていることを確認する方法について、詳細をご確認ください。

マイクとカメラのインジケーター

Android 12 以降を搭載しているデバイスでは、アプリがマイクまたはカメラにアクセスすると、ステータスバーにアイコンが表示されます。

これらのインジケーターについて、またアプリが CAMERA および RECORD_AUDIO 権限に関するベスト プラクティスに沿っていることを確認する方法について、詳細をご確認ください。

「カメラへのアクセス」、「マイクへのアクセス」というラベルが付いたクイック設定タイル。
図 2. クイック設定でのマイクとカメラの切り替え
右上隅に角の丸い長方形があり、その中にカメラアイコンとマイクアイコンがある
図 3. 最近のデータアクセスが表示されるマイクとカメラのインジケーター。

権限パッケージの公開設定

Android 12 以降を搭載したデバイスでは、Android 11(API レベル 30)以降をターゲットとし、以下のいずれかのメソッドを呼び出すアプリは、他のアプリに対するアプリのパッケージの公開設定に基づいてフィルタされた結果セットを受け取ります。

BouncyCastle の実装を削除

Android 12 では、すべての AES アルゴリズムを含め、これまで非推奨となっていた多数の暗号アルゴリズムの BouncyCastle 実装が削除されました。代わりに、システムはこれらのアルゴリズムの Conscrypt 実装を使用します。

次のいずれかに該当する場合、この変更はアプリに影響します。

  • アプリが 512 ビットの鍵サイズを使用する。Conscrypt はこの鍵サイズをサポートしていません。必要に応じて、異なる鍵サイズを使用するよう、アプリの暗号ロジックを更新します。
  • アプリが KeyGenerator で無効な鍵サイズを使用する。Conscrypt の KeyGenerator の実装では、BouncyCastle と比較して、鍵パラメータに対して追加の検証が行われます。たとえば、AES は 128 ビット、192 ビット、256 ビットの鍵しかサポートしていないため、Conscrypt では 64 ビットの AES 鍵を生成できません。

    BouncyCastle では無効なサイズの鍵を生成できますが、その鍵を Cipher で使用すると後で失敗します。Conscrypt は先に失敗します。

  • 12 バイト以外のサイズを使用して Galois/Counter Mode(GCM)暗号を初期化する。Conscrypt の GcmParameterSpec の実装では、NIST が推奨する 12 バイトの初期化が必要です。

クリップボードへのアクセスの通知

Android 12 以降では、アプリが初めて getPrimaryClip() を呼び出して、別のアプリからクリップデータにアクセスすると、トースト メッセージによって、このクリップボードへのアクセスがユーザーに通知されます。

トースト メッセージ内のテキストには、APP pasted from your clipboard. の形式が含まれます。

クリップの説明のテキストに関する情報

Android 12 以降では、getPrimaryClipDescription() が次の詳細を検出できます。

アプリからシステム ダイアログを閉じるアクションが不可に

アプリとシステムを操作しているときのユーザー制御を改善するため、Android 12 では ACTION_CLOSE_SYSTEM_DIALOGS インテント アクションのサポートが終了しました。少数の特殊なケースを除いて、アプリがこのアクションを含むインテントの呼び出しを試みると、アプリのターゲット SDK バージョンに応じてシステムは次のいずれかを行います。

  • アプリが Android 12 以降を対象にしている場合、SecurityException が発生します。
  • Android 11(API レベル 30)以下をターゲットとするアプリの場合は、インテントを実行しません。logcat には次のメッセージが表示されます。

    E ActivityTaskManager Permission Denial: \
    android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \
    com.package.name requires android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \
    dropping broadcast.
    

例外

次の場合、アプリは Android 12 以降で引き続きシステム ダイアログを閉じることができます。

  • アプリがインストルメンテーション テストを実行している。
  • アプリが Android 11 以下をターゲットとしており、通知ドロワーの上にウィンドウを表示している。

  • アプリが Android 11 以下をターゲットとしている。さらに、ユーザーが(おそらく通知のアクション ボタンを使用して)通知を操作し、アプリがそのユーザー アクションに応じてサービスまたはブロードキャスト レシーバを処理している。

  • アプリが Android 11 以前をターゲットとしており、ユーザー補助サービスが有効になっている。アプリが Android 12 をターゲットとし、通知バーを閉じる場合は、代わりに GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE ユーザー補助アクションを使用します。

信頼できないタッチイベントはブロックされる

システム セキュリティと優れたユーザー エクスペリエンスを維持するため、Android 12 は、オーバーレイが安全でない方法でアプリを覆い隠している場合にタッチイベントをアプリが使用することを許しません。つまり、少数の例外を除いて、特定のウィンドウをパススルーするタッチはシステムによってブロックされます。

影響を受けるアプリ

この変更は、たとえば FLAG_NOT_TOUCHABLE フラグを使用してタッチにウィンドウをパススルーさせているアプリに影響します。具体例の一部を以下に示します。

  • TYPE_APPLICATION_OVERLAY を使用し、FLAG_NOT_TOUCHABLE フラグを使用するウィンドウなど、SYSTEM_ALERT_WINDOW 権限を必要とするオーバーレイ。
  • FLAG_NOT_TOUCHABLE フラグを使用するアクティビティ ウィンドウ。

例外

次の場合は「パススルー」タッチが許可されます。

  • アプリ内の操作: アプリがオーバーレイを表示し、ユーザーがアプリを操作しているときにのみオーバーレイが表示されます。
  • 信頼済みのウィンドウ: 信頼済みのウィンドウの例の一部を次に示します。

  • 不可視のウィンドウ: ルートビューが GONE または INVISIBLE のウィンドウ。

  • 完全に透明なウィンドウ: alpha プロパティが 0.0 のウィンドウ。

  • 十分に透明なシステム アラート ウィンドウ: 不透明度の組み合わせの総和がタッチに対するシステムの最大隠蔽不透明度以下である場合、一連のシステム アラート ウィンドウは十分に透明であると見なされます。Android 12 では、この最大不透明度はデフォルトで 0.8 になっています。

信頼できないタッチがブロックされたときに検出する

タッチ アクションがシステムによってブロックされると、logcat は次のメッセージを記録します。

Untrusted touch due to occlusion by PACKAGE_NAME

変更をテストする

Android 12 以降を搭載したデバイスでは、信頼できないタッチはデフォルトでブロックされます。信頼できないタッチを許可するには、ターミナル ウィンドウで次の adb コマンドを実行します。

# A specific app
adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
# If you'd still like to see a Logcat message warning when a touch would be
# blocked, use 1 instead of 0.
adb shell settings put global block_untrusted_touches 0

動作をデフォルト(信頼できないタッチがブロックされる)に戻すには、次のコマンドを実行します。

# A specific app
adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
adb shell settings put global block_untrusted_touches 2

アクティビティのライフサイクル

戻るボタンを押してもルート ランチャー アクティビティが終了しない

Android 12 では、タスクのルートにあるランチャー アクティビティの戻るボタンのデフォルト処理が変更されています。以前のバージョンでは、これらのアクティビティを戻るボタンを押して終了していました。Android 12 では、アクティビティを終了する代わりに、アクティビティとそのタスクをバックグラウンドに移動させるようになりました。 この新しい動作は、ホームボタンやジェスチャーを使用してアプリから移動する際の現在の動作と一致しています。

ほとんどのアプリでは、この変更により、戻るボタンでアプリを終了した場合に、コールド状態からアプリを再起動するのではなく、ウォーム状態からすばやくアプリを再開できるようになります。

この変更についてアプリをテストすることをおすすめします。アプリで onBackPressed() をオーバーライドすることで「戻る」ナビゲーションを処理し、Activity を終了していた場合は、終了せずに super.onBackPressed() を呼び出すように実装を更新してください。super.onBackPressed() を呼び出すと、必要に応じてアクティビティとそのタスクがバックグラウンドに移動し、アプリ間で一貫性のあるナビゲーションを実現できます。

また一般に、onBackPressed() をオーバーライドする代わりに、AndroidX Activity API を使用して「戻る」カスタム ナビゲーションを提供することをおすすめします。戻るボタンをインターセプトするコンポーネントがない場合、AndroidX Activity API は自動的に適切なシステム動作に従います。

グラフィックと画像

リフレッシュ レートの切り替えの改善

Android 12 では、ディスプレイが新しいリフレッシュ レートへのシームレスな移行をサポートするかどうかにかかわらず、setFrameRate() を使用してリフレッシュ レートを変更できます。シームレスな移行とは、画面が 1~2 秒黒くなるなどの視覚的な中断がないことを指します。これまでは、ディスプレイがシームレスな移行をサポートしていない場合、setFrameRate() が呼び出された後も通常は同じリフレッシュ レートを使用し続けていました。getAlternativeRefreshRates() を呼び出すことで新しいリフレッシュ レートへの移行がシームレスに行われるかどうかを事前に判断できます。一般に、コールバック onDisplayChanged() はリフレッシュ レートの切り替えが終わった後に呼び出されますが、一部の外部接続ディスプレイでは、シームレスでない移行の間に呼び出されます。

実装例を次に示します。

Kotlin

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
val refreshRates = this.display?.mode?.alternativeRefreshRates
val willBeSeamless = Arrays.asList<FloatArray>(refreshRates).contains(newRefreshRate)

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)

Java

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
Display display = context.getDisplay(); // API 30+
Display.Mode mode = display.getMode();
float[] refreshRates = mode.getAlternativeRefreshRates();
boolean willBeSeamless = Arrays.asList(refreshRates).contains(newRefreshRate);

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS);

接続性

Passpoint の更新

Android 12 では、次の API が追加されています。

  • isPasspointTermsAndConditionsSupported(): 利用規約Passpoint 機能であり、ネットワーク デプロイにおいて、オープン ネットワークを使用する安全でないキャプティブ ポータルを安全な Passpoint ネットワークに置き換えることができます。利用規約への同意が必要な場合は、通知が表示されます。利用規約によって制限される Passpoint ネットワークを提案するアプリでは、まずこの API を呼び出して、デバイスが機能をサポートしていることを確認する必要があります。デバイスが機能をサポートしていない場合、このネットワークには接続できず、代替ネットワークまたはレガシー ネットワークを提案する必要があります。
  • isDecoratedIdentitySupported(): プレフィックス装飾でネットワークの認証を行う場合、装飾された ID プレフィックスにより、ネットワーク事業者はネットワーク アクセス識別子(NAI)を更新して、AAA ネットワーク内の複数のプロキシを経由して明示的なルーティングを行えます(詳細については RFC 7542 をご覧ください)。

    Android 12 では、PPS-MO 拡張の WBA 仕様に適合するようにこの機能が実装されています。装飾された ID を必要とする Passpoint ネットワークを提案するアプリでは、まずこの API を呼び出して、デバイスが機能をサポートしていることを確認する必要があります。デバイスが機能をサポートしていない場合、ID が装飾されず、ネットワークの認証が失敗する可能性があります。

Passpoint の提案を作成するには、アプリで PasspointConfigurationCredentialHomeSp クラスを使用する必要があります。これらのクラスは、Wi-Fi Alliance Passpoint 仕様で定義されている Passpoint プロファイルを記述します。

詳しくは、インターネット接続のための Wi-Fi サジェスチョン API をご覧ください。

非 SDK インターフェースの制限の更新

Android 12 では、Android デベロッパーの協力と直近の内部テストに基づいて、制限を受ける非 SDK インターフェースのリストが更新されています。Google は、非 SDK インターフェースを制限する前に、可能な限り、その代わりとなる公開インターフェースを利用可能にしています。

Android 12 をターゲットとしないアプリでは、この変更の一部はすぐには影響しない可能性があります。ただし、現時点で(アプリのターゲット API レベルに応じて)一部の非 SDK インターフェースを利用できていても、非 SDK のメソッドまたはフィールドをそのまま使用し続けると、将来的にアプリが機能しなくなるリスクが高くなります。

アプリが非 SDK インターフェースを使用しているかどうか不明な場合は、アプリをテストして確認できます。アプリが非 SDK インターフェースに依存している場合は、SDK の代替インターフェースへの移行を計画してください。ただし Google も、一部のアプリには非 SDK インターフェースを使用する正当なユースケースがあると承知しています。アプリの機能で使用している非 SDK インターフェースの代替インターフェースが見つからない場合は、新しい公開 API をリクエストしてください。

Android の今回のリリースの変更について詳しくは、非 SDK インターフェースの制限に関する Android 12 での変更点をご覧ください。非 SDK インターフェース全般について詳しくは、非 SDK インターフェースの制限をご覧ください。