#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にしたりすることができます。