코딩 일기장/Android(Kotlin)

[Android/Kotlin]Detect Screen Capture Event/캡쳐 탐지/캡쳐 시 스낵바 띄우기

minWachya 2022. 5. 27. 22:03
반응형

 

... 무신사 앱으로 옷 좀 보다가 너무 귀여워서 캡쳐했는데,,,

내가 캡쳐한 사진을 공유하겠나고 토스트를 띄운 거임??

아니 내가 캡쳐한 거 어케 알았지!?!?!?

너무너무 신기해서 나도 만들어보고 싶었다.

아래는 무신사에서 캡쳐하면 나오는 토스트다.

이거 토끼랑 강아지 검색했더니 나옴

진짜 열심히 찾았는데 공식에서 제공해주는 이벤트 리스너는 없고,

대신... 깃허브에서 라이브러리를 찾음!!

 

얼릉만들어보자

 

결과 화면


1. 라이브러리 추가

// 스크린샷 탐지
implementation 'com.akexorcist:screenshot-detection:1.0.2'

 

2. 코드 짜기(깃허브 리드미에 잘 설명되어져 있음)

package com.example.mycapture

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.akexorcist.screenshotdetection.ScreenshotDetectionDelegate
import com.example.mycapture.custom.CustomToast.showCustomToast
import com.example.mycapture.databinding.ActivityCaptureBinding
import com.google.android.material.snackbar.Snackbar
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*

private lateinit var binding: ActivityCaptureBinding
private const val TAG = "mmmCaptureActivity"

// 캡쳐하기 화면
class CaptureActivity : AppCompatActivity(), ScreenshotDetectionDelegate.ScreenshotDetectionListener {
    // 켑쳐 탐지기
    private val screenshotDetectionDelegate = ScreenshotDetectionDelegate(this@CaptureActivity, this@CaptureActivity)
    // 캡쳐 후 저장에 관한 권한 코드
    companion object { private const val REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION = 3009 }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityCaptureBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        // 권한 확인
        checkReadExternalStoragePermission()

    }

    override fun onStart() {
        super.onStart()
        screenshotDetectionDelegate.startScreenshotDetection()
    }

    override fun onStop() {
        super.onStop()
        screenshotDetectionDelegate.stopScreenshotDetection()
    }

    // 화면 캡쳐 시 이벤트
    override fun onScreenCaptured(path: String) {
        // path: /storage/emulated/0/DCIM/Screenshots/Screenshot_20220527-211810_MyCapture.jpg
        val bitmap = BitmapFactory.decodeFile(path)
        Toast(applicationContext).showCustomToast(applicationContext, bitmap, "방금 찍은 화면을 공유해보세요!")
    }
    // 화면 캡쳐를 위한 권한이 설정되지 않았을 때
    override fun onScreenCapturedWithDeniedPermission() {
        Toast.makeText(applicationContext, "캡쳐를 위해 권한을 설정해주세요.", Toast.LENGTH_SHORT).show()
    }
    // 권한 요청에 대한 응답 함수
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        when (requestCode) {
            REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION -> {
                // 권한이 거부되었을 때
                if (grantResults.getOrNull(0) == PackageManager.PERMISSION_DENIED)
                    Toast.makeText(this@CaptureActivity,
                        "Read External Storage 권한이 거부되었습니다.", Toast.LENGTH_SHORT).show()
            }
            else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }
    // 권한 확인 함수
    private fun checkReadExternalStoragePermission() {
        if (ContextCompat.checkSelfPermission(this@CaptureActivity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestReadExternalStoragePermission()
        }
    }
    // 권한 요청 함수
    private fun requestReadExternalStoragePermission() {
        ActivityCompat.requestPermissions(this@CaptureActivity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION)
    }

}

 

3. custom_toast.xml 생성

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/custom_toast_background"
    android:padding="10dp">

    <ImageView
        android:id="@+id/imgView"
        android:layout_width="50dp"
        android:layout_height="60dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/custom_toast_text"
        android:textColor="@color/white"
        android:textSize="14sp"
        android:layout_marginStart="10dp"
        app:layout_constraintBottom_toBottomOf="@+id/imgView"
        app:layout_constraintStart_toEndOf="@+id/imgView"
        app:layout_constraintTop_toTopOf="@+id/imgView" />

    <TextView
        android:id="@+id/btnShare"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/custom_toast_btn"
        android:textColor="@color/purple_200"
        android:textSize="14sp"
        android:layout_marginStart="20dp"
        app:layout_constraintBottom_toBottomOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="@+id/textView" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

참고로  drawable>custom_toast_background.xml은 아래와 같다

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#aa000000" />
    <corners android:radius="10dp" />
</shape>

 

4. CustomToast.kt 생성

package com.example.mycapture.custom

import android.content.Context
import android.graphics.Bitmap
import android.view.Gravity
import android.view.LayoutInflater
import android.widget.Toast
import com.example.mycapture.R
import com.example.mycapture.databinding.CustomToastBinding

// 커스텀 토스트
object CustomToast {
    fun Toast.showCustomToast(context: Context, image: Bitmap, message: String) {
        val layout = LayoutInflater.from(context).inflate(R.layout.custom_toast,null)
        val binding = CustomToastBinding.bind(layout)
        // 이미지 설정
        binding.imgView.setImageBitmap(image)
        // 텍스트 설정
        binding.textView.text = message
        // show
        this.apply {
            setGravity(Gravity.TOP, 0, 80)
            duration = Toast.LENGTH_SHORT
            view = layout
            show()
        }
    }
}

참고

https://github.com/akexorcist/ScreenshotDetection

 

GitHub - akexorcist/ScreenshotDetection: [Android] Screenshot detection while user using your app

[Android] Screenshot detection while user using your app - GitHub - akexorcist/ScreenshotDetection: [Android] Screenshot detection while user using your app

github.com

 

https://www.youtube.com/watch?v=xSkRwRapBrE 

 

반응형