Mokelab Blog

#31 Androidでスクリーンショットを禁止する

Google認証システム アプリなど、一部のアプリでスクリーンショットを取ろうとすると、次のような通知が表示され、スクリーンショットがとれません。

これを開発しているアプリで実現するには、次のようにwindowに対してFLAG_SECUREフラグを設定します。 アクティビティ毎に設定する必要があるので、複数アクティビティで構成されている場合は設定忘れに注意しましょう。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)

        setContentView(R.layout.activity_main)

    }
}

なお、このフラグがアクティビティについている場合、オーバービュー画面(アプリ切り替え画面)でプレビュー表示されなくなります。次の図はChromeのシークレットタブを表示している図です。

window.setFlags()

ところで、windowに対してフラグを設定するメソッドとして、setFlags()というメソッドもあります。 このメソッドは引数を2つとり、第2引数にはマスク用の値を渡してねとあります。なぜこのような形になっているのでしょうか?

フラグは、ビットフラグで扱われています。1ビット目が1だったら、この機能がONという意味になっています。そのため、第1引数のフラグの値をそのままセットすると、 他のフラグの値が失われてしまうことになります。例えば現在の値が1001で、セットする値が0100だった場合、次のようになってしまいます。

value  0100
prev   1001
-----------
next   0100

第1引数のフラグ値とORをとれば、指定したビットだけ1にすることができそうです。

value  0100
prev   1001
-----------
next   1101

しかし、この方法だと指定したビットを0に戻すことができません。そこで登場するのが第2引数のマスクです。1にしたビットのみを変更する役割をもちます。 「今の値と~マスク値のAND」と、「セットする値とマスク値のAND」をとります。そしてその結果をORしてみます。

mask       0100
value      0100
prev       1001
---------------
value&mask 0100
prev&~mask 1001
---------------
next       1101

指定したビットがすでに1だった場合はどうでしょうか?

mask       0100
value      0100
prev       1101 <- すでに1になっている
---------------
value&mask 0100
prev&~mask 1001
---------------
next       1101

セットする値を0にした場合も見てみましょう。

mask       0100
value      0000
prev       1001
---------------
value&mask 0000
prev&~mask 1001
---------------
next       1001
mask       0100
value      0000
prev       1101 <- すでに1になっている
---------------
value&mask 0000
prev&~mask 1001
---------------
next       1001

このように、第2引数にマスクを用意することで、指定したビットを1にしたり、0にしたりすることができます。

本サイトではサービス向上のため、Google Analyticsを導入しています。分析にはCookieを利用しています。