Android: How to show partial transparent overlay but still send all events to views below

43 Views Asked by At

I want to show a partial translucent overlay through the entire lifecycle of the app. I also want the overlay NOT to consume any events and pass the events down. I am able to draw the overlay but underlying views are not getting the views covered by the overlay. Outside overlay is fine.

Here is my code:

package com.example.demo

import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.PixelFormat
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.widget.Button
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope

class MainActivity : AppCompatActivity() {
    private val PERMISSION_REQUEST_CODE = 1
    private lateinit var overlayView: View
    private lateinit var windowManager: WindowManager
    private lateinit var params: WindowManager.LayoutParams

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
        overlayView = inflater.inflate(R.layout.popup, null)

        params = WindowManager.LayoutParams(
            300,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
                    WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT
        )
        params.gravity = Gravity.END
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager

        findViewById<Button>(R.id.btn_show_overlay).setOnClickListener {
            if (checkOverlayPermissionRequest()) {
                if (!overlayView.isShown) {
                    showPopupOverlay()
                } else {
                    windowManager.removeView(overlayView)
                }
            }
        }
    }

    private fun checkOverlayPermissionRequest(): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                val intent = Intent(
                    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:$packageName")
                )
                startActivityForResult(intent, PERMISSION_REQUEST_CODE)
                return false
            }
        }
        return true
    }

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (!overlayView.isShown) {
                    showPopupOverlay()
                } else {
                    windowManager.removeView(overlayView)
                }
            }
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @RequiresApi(Build.VERSION_CODES.O)
    private fun showPopupOverlay() {
        windowManager.addView(overlayView, params)
        overlayView.setOnTouchListener { v, event ->
            false
        }
    }
}

Popup:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/overlay"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello, popup!"
        android:gravity="center"
        />
</RelativeLayout>

Main:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/cl_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_start_demo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Launch Demo Activity"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/btn_show_overlay"

        />

    <Button
        android:id="@+id/btn_show_overlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show overlay"
        app:layout_constraintTop_toBottomOf="@id/btn_start_demo"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

Target SDK version: 33

enter image description here

0

There are 0 best solutions below