【Android】FLAG_SECUREで画面のスクリーンショットを制限する

## はじめに
個人情報等の機密情報を取り扱うアプリでは、ユーザーからのスクリーンショットや画面録画を制限したいケースが出てかもと思います。
Androidでは、特定の画面（Activity）に対してスクリーンショットや画面録画を制限する機能があるので、上記のようなケースに対応することが可能です。
今回はクリーンショットや画面録画を制限する機能についてまとめたいと思います。

## FLAG_SECUREとは
スクリーンショットや画面録画を制限したい対象のActivityに設定するフラグになります。

## 実装
実装は簡単。
setFlagsでFLAG_SECUREを設定してあげればOKです。

``` MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        // ここの部分を追加すればOK
        this.window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
    }
}
```
実際スクリーンショット・画面録画をしてみると、画像が真っ黒で保存されるようになります。

## 【おまけ】スクリーンショットの検出
スクリーンショットの制限とは少し話がそれますが、Android OS14以上ではスクリーンショットの実行を検出できるようになりました。
コールバックを設定することができ、スクリーンショットをトリガーに処理を実行することが可能です。
こちらも割と簡単に実装できます。
### Manifestにパーミッションを追加
以下のパーミッションをManifestに追加します。
``` AndroidManifest.xml
<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
```
### スクリーンショット実行時のコールバックを定義
ScreenCaptureCallbackを使い、スクリーンショットを検出した時に実行する処理を記載します。
今回はログ出力を行うようにしています。
``` MainActivity.kt
class MainActivity : AppCompatActivity() {
    val screenCaptureCallback = ScreenCaptureCallback {
        Log.d("CaptureRestrictionSample", "スクリーンショットを検出")
    }
    ・
    ・
    ・
}
```

### スクリーンショットのコールバックを設定
registerScreenCaptureCallbackを使用し、スクリーンショット検出時のコールバックを設定します。
この機能はOS14以上でしか使えないため、実行の前にOSレベルの判定を入れています。
``` MainActivity.kt
    override fun onStart() {
        super.onStart()

        // OS 14以上の場合に使用できる機能
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            registerScreenCaptureCallback(mainExecutor, screenCaptureCallback)
        }
    }
```

### スクリーンショットのコールバックを解除
unregisterScreenCaptureCallbackで登録したコールバックを解除します。
``` MainActivity.kt
    override fun onStop() {
        super.onStop()
        // OS 14以上の場合に使用できる機能
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            unregisterScreenCaptureCallback(screenCaptureCallback)
        }
    }
```

実際にスクリーンショットを撮ってみると、以下のように画面の下部にメッセージが表示されるようになります。
このメッセージはOS側で出しているものなので、アプリ側からはコントロールできなそうです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512668/923b8378-f2e1-8882-1873-7daf1347c405.png" width=40% height=40%>

## おわりに
今回はスクリーンショットや画面録画を制限する機能についてまとめてみました。
割と簡単に導入できるようなので、アプリ情報を端末に画像や動画として保存されたくない場合には使っていきたいなと思います。

また、おまけとして、OS14で追加されたスクリーンショットを検出する機能も取り上げてみました。
スクリーンショットを検出してダイアログ等でメッセージを表示したい、という要件があれば使えるものかと思います。

（どうやらOS15では画面録画を検出する機能も追加されるようです。詳しくは[こちら](https://www.droidcon.com/2024/06/24/screen-recording-detection-android-15/)）

## 参考
- [ユーザーがデバイスのスクリーンショットを撮影したときに検出する](https://developer.android.com/about/versions/14/features/screenshot-detection?hl=ja)
- [Android 15’s Screen Recording Detection](https://alisubhani313.medium.com/android-15s-screen-recording-detection-27349f8873cf)