Giới thiệu về FLAG_SECURE
Để ngăn chặn screenshot (chụp màn hình) và screen recording khi app vào background hoặc foreground, sử dụng WindowManager.LayoutParams.FLAG_SECURE.
Cờ này làm cho nội dung cửa sổ được coi là "bảo mật" - hệ thống sẽ chặn screenshot, screen record, và hiển thị màn hình đen trong recent apps.
Ví dụ minh họa
Bước 1: Tạo project
Android Studio → File → New Project.
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/parent"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/openYoutube"
android:text="Open youtube application"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Bước 3: Code (src/MainActivity.java)
package com.example.andy.myapplication;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.WindowManager;
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// QUAN TRỌNG: Gọi TRƯỚC setContentView()
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
setContentView(R.layout.activity_main);
}
}
Giải thích code
// Bật FLAG_SECURE cho cửa sổ hiện tại
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
Hiệu quả của FLAG_SECURE
- Screenshot: Hệ thống chặn, lưu ảnh đen hoặc thông báo "Couldn't capture screenshot"
- Screen recording: Nội dung app bị đen/mờ trong video quay màn hình
- Recent apps: Thumbnail hiển thị đen hoặc icon app mặc định
- Remote display: Không hiển thị trên Chromecast, Miracast
- Accessibility: Một số service accessibility bị hạn chế
Áp dụng cho toàn bộ App (BaseActivity)
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Bật secure cho tất cả activity kế thừa
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
super.onCreate(savedInstanceState);
}
}
// Các activity khác
public class MainActivity extends BaseActivity { ... }
public class LoginActivity extends BaseActivity { ... }
Áp dụng cho Dialog/BottomSheet
// Dialog
Dialog dialog = new Dialog(this);
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
// BottomSheetDialog
BottomSheetDialog dialog = new BottomSheetDialog(this);
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
Tắt FLAG_SECURE khi cần cho phép screenshot
// Bỏ cờ secure getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
Lưu ý quan trọng
- Gọi TRƯỚC setContentView() - quan trọng!
- Không ngăn chặn được: chụp ảnh bằng camera vật lý, root screen capture
- Có thể ảnh hưởng accessibility (TalkBack, Switch Access)
- Test trên nhiều thiết bị - một số OEM có hành vi khác
- Không dùng cho toàn bộ app nếu không cần thiết (giảm UX)
Kiểm tra FLAG_SECURE đang bật
boolean isSecure = (getWindow().getAttributes().flags
& WindowManager.LayoutParams.FLAG_SECURE) != 0;
Use cases phổ biến
- Màn hình đăng nhập/OTP (banking, payment)
- Màn hình hiển thị dữ liệu nhạy cảm (CMND, thẻ tín dụng)
- Premium content (DRM video, document)
- Enterprise app (DLP - Data Loss Prevention)