Android 5(API レベル 21)で導入されたメディア プロジェクション API を使用すると、デバイス ディスプレイのコンテンツをメディア ストリームとしてキャプチャし、テレビなどの他のデバイスで再生、録画、キャストできます。
メディア プロジェクションは、デバイス ディスプレイにおける次の 3 つの表現に対応しています。

Surface
に書き込む。
メディア プロジェクションでは、デバイス ディスプレイのコンテンツをキャプチャし、キャプチャした画像を仮想ディスプレイに投影して、Surface
にレンダリングします。
アプリは、キャプチャされたディスプレイのコンテンツを使用する SurfaceView
または ImageReader
によって Surface
を提供します。ImageReader
の OnImageAvailableListener
を使用すると、Surface
でレンダリングされる画像をリアルタイムで管理できます。録画として画像を保存したり、テレビなどのデバイスにキャストしたりできます。
メディア プロジェクション
メディア プロジェクション セッションを開始するには、ディスプレイのコンテンツ、デバイス オーディオ、またはその両方をキャプチャする権限をアプリに付与するトークンを取得します。トークンは、MediaProjection
クラスのインスタンスで表されます。このクラスのインスタンスは、新しいアクティビティの開始時に作成できます。
以前の方法
以前の方法でメディア プロジェクション トークンを取得するには、MediaProjectionManager
システム サービスの createScreenCaptureIntent()
メソッドによって返されたインテントを使用して、startActivityForResult()
を呼び出します。
Kotlin
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION)
Java
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
この呼び出しによって、表示されたすべての情報(機密情報や個人を特定できる情報を含む)がメディア プロジェクションによってキャプチャされたことをユーザーに通知する、確認ダイアログ ボックスが表示されます。
ユーザーが確認すると、startActivityForResult()
が onActivityResult()
コールバックに結果コードとデータを渡します。
次に MediaProjectionManager
から getMediaProjection()
メソッドにデータと結果コードを渡して、MediaProjection
のインスタンスを作成できます。
Kotlin
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData)
Java
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);
推奨の方法
メディア プロジェクション トークンを取得する推奨の方法では、Jetpack Activity ライブラリの API を使用します。
Kotlin
val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java) var mediaProjection : MediaProjection val startMediaProjection = registerForActivityResult( StartActivityForResult() ) { result -> if (result.resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager .getMediaProjection(result.resultCode, result.data!!) } } startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())
Java
final MediaProjectionManager mediaProjectionManager = getSystemService(MediaProjectionManager.class); final MediaProjection[] mediaProjection = new MediaProjection[1]; ActivityResultLauncher<Intent> startMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
仮想ディスプレイ
メディア プロジェクションの中心となるのは仮想ディスプレイです。仮想ディスプレイは、MediaProjection
インスタンスで createVirtualDisplay()
を呼び出して作成します。
Kotlin
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null)
Java
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
width
および height
パラメータは、仮想ディスプレイの幅と高さを指定します。メディア プロジェクションの幅と高さに一致する値を取得するには、Android 11(API レベル 30)で導入された WindowMetrics
API を使用します。
WindowMetrics
メディア プロジェクションを作成するアプリが全画面モードとマルチ ウィンドウ モードのどちらで実行されているかにかかわらず、メディア プロジェクションはディスプレイ全体をキャプチャします。
メディア プロジェクションの寸法を取得するには、WindowManager#getMaximumWindowMetrics()
を使用します。このメソッドは、メディア プロジェクション アプリがマルチ ウィンドウ モードで実行されていてディスプレイの一部だけを占有している場合であっても、ディスプレイ全体を表す WindowMetrics
オブジェクトを返します。
API レベル 14 までの互換性をさかのぼって確保するには、Jetpack WindowManager ライブラリの WindowMetricsCalculator#computeMaximumWindowMetrics()
を使用します。
メディア プロジェクションの仮想ディスプレイの正しい幅と高さを取得するには、WindowMetrics#getBounds()
を呼び出します(仮想ディスプレイを参照)。
メディア プロジェクション アプリは、必ずサイズ変更可能にしてください。サイズ変更が可能なアプリは、デバイス設定の変更とマルチウィンドウ モードをサポートします(マルチウィンドウのサポートをご覧ください)。
アプリがサイズ変更不可の場合は、ウィンドウ コンテキストから表示境界をクエリし、WindowManager#getMaximumWindowMetrics()
を使用して、アプリで利用可能な最大表示領域の WindowMetrics
を取得する必要があります。
Kotlin
val windowContext = context.createWindowContext(context.display!!, WindowManager.LayoutParams.TYPE_APPLICATION, null) val projectionMetrics = windowContext.getSystemService(WindowManager::class.java) .maximumWindowMetrics
Java
Context windowContext = context.createWindowContext(context.getDisplay(), WindowManager.LayoutParams.TYPE_APPLICATION, null); WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics();
Surface
必要な解像度で出力を生成するには、メディア プロジェクション サーフェスのサイズを調整する必要があります。テレビやパソコンのモニターに画面をキャストする場合は大きいサイズ(低解像度)に、デバイスのディスプレイを録画する場合は小さいサイズ(高解像度)にします。
12L(API レベル 32)以降では、サーフェスで仮想ディスプレイをレンダリングする際に、ImageView
の centerInside
オプションと同様のプロセスを使用して、仮想ディスプレイがサーフェスに合わせてスケーリングされます。
この新しいスケーリング方法により、適切なアスペクト比を維持しながら、サーフェス画像のサイズを最大化することで、テレビや他の大型ディスプレイに画面をキャストしやすくなります。
おすすめ
メディア プロジェクションで最適な結果を得るための推奨事項を示します。
- アプリのサイズを変更できるようにします。サイズ変更が可能なアプリは、デバイス設定の変更とマルチウィンドウ モードをサポートします(マルチウィンドウのサポートをご覧ください)。アプリ マニフェストで
resizeableActivity="true"
を設定します。Android 7.0(API レベル 24)以降では、この設定がデフォルトで true になっています。 - スマートフォン、タブレット、折りたたみ式フォーム ファクタは一般的に横向きと縦向きの両方に対応しているため、アプリも横向きと縦向きの両方をサポートするようにします。
WindowManager#getMaximumWindowMetrics()
を使用して、メディア プロジェクションの境界を取得します。API レベル 14 までの互換性を確保するには、Jetpack WindowManager を使用します(WindowMetrics セクションを参照)。- アプリのサイズを変更できない場合は、ウィンドウ コンテキストからメディア プロジェクションの境界を取得します(WindowMetrics セクションを参照)。
参考情報
メディア プロジェクションの詳細については、動画と音声の再生のキャプチャをご覧ください。