Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to overlay a layout on lock screen when in devices running Oreo and Pie

In my application i'm trying to overlay a layout with a service here when i'm running service it successfully executes and display the layout on lock screen when target devices is lower than oreo but when i'm trying to overlay the same from versions later than oreo it's not working however when i change the flag to Type_Application_Overlay as suggested in other answers it just display layout when screen is unlocked but i want to show it over lock screen i tried searching a lot but didn't find any helpful answers to solving this problem some answers suggested displaying an activity over lockscreen i tried that too but still that didn't prove to be of any help!

Moreover, To add on there are some apps on play store which can easily display any layout over a lock screen even on oreo and pie:

You can take a look at this app:

https://play.google.com/store/apps/details?id=com.wifihacker.whousemywifi.wifirouter.wifisecurity

This app easily display a custom full screen layout over lockscreen even without asking for any overlay permission or device admin permissions.

So if this app is able to overlay over lock screen why am i unable to do the same?

Any help and suggestions into this will be really appreciated!

Here's is my current service code for lock screen:

class LockScreenService : Service() {

    private lateinit var mReceiver: BroadcastReceiver
    private var isShowing = false

    private lateinit var windowManager: WindowManager
    lateinit var  params: WindowManager.LayoutParams
    lateinit var myview: View
    var  downX:Int = 0
    lateinit var locklayout:RelativeLayout
     var upX:Int = 0
    var indicator: WaveLoadingView?=null
    lateinit var date:TextView
    lateinit var time:TextView
    lateinit var settings:ImageView
    lateinit var unlock:LinearLayout
    var r:Runnable?=null
    companion object{

    }
    private val mBatInfoReceiver = object : BroadcastReceiver() {
        override fun onReceive(ctxt: Context, intent: Intent) {
            val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
            if (indicator!=null)
            {
                indicator!!.progressValue = level
                indicator!!.setAnimDuration(3000)
                indicator!!.startAnimation()
            }
            }
    }

    override fun onBind(intent: Intent): IBinder? {
        // TODO Auto-generated method stub
        return null
    }

    override fun onCreate() {
        super.onCreate()
        try {
            EventBus.getDefault().register(this)
            windowManager = applicationContext.getSystemService(WINDOW_SERVICE) as WindowManager

            val li = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

            myview = li.inflate(R.layout.lockscreenlayout, null)
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                params = WindowManager.LayoutParams(
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT
                )
            } else {
                params = WindowManager.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                            or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                            or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                            or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                    PixelFormat.TRANSLUCENT
                )
                myview.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            or View.SYSTEM_UI_FLAG_FULLSCREEN
                            or View.SYSTEM_UI_FLAG_VISIBLE
                            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                            or View.SYSTEM_UI_FLAG_IMMERSIVE
                            or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                )
            }
            myview.setVisibility(View.VISIBLE)
            settings = myview.findViewById(R.id.imgsetting)
            settings.setOnClickListener {
                var intent = Intent(this, Settings::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                this.startActivity(intent)
                windowManager.removeViewImmediate(myview)
            }

             indicator = myview.findViewById(R.id.indicator)
            locklayout = myview.findViewById(R.id.locklay)
            this.registerReceiver(this.mBatInfoReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
            time = myview.findViewById(R.id.time)
            date = myview.findViewById(R.id.date)

            date.text =
                SimpleDateFormat("EEEE").format(Calendar.getInstance().time).toString() + "," + SimpleDateFormat("dd").format(
                    Calendar.getInstance().time
                ).toString() + " " + SimpleDateFormat("MMMM").format(Calendar.getInstance().time).toString()
            try {
                unlock.setOnTouchListener(object : View.OnTouchListener {
                    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                        if (event!!.getAction() == MotionEvent.ACTION_DOWN) {
                            downX = event.getX().toInt()

                            return true
                        } else if (event.getAction() == MotionEvent.ACTION_UP) {
                            upX = event.getX().toInt()
                            if (upX - downX > 100) {
                                val animation = AnimationUtils.loadAnimation(applicationContext, R.anim.left_right_anim)
                                animation.setAnimationListener(object : Animation.AnimationListener {
                                    override fun onAnimationStart(animation: Animation) {}

                                    override fun onAnimationRepeat(animation: Animation) {}

                                    override fun onAnimationEnd(animation: Animation) {
                                        windowManager.removeViewImmediate(myview)
                                    }
                                })
                                locklayout.startAnimation(animation)
                                // swipe right
                            } else if (downX - upX > -100) {

                            }
                            return true

                        }
                        return false
                    }
                })
            } catch (ex: Exception)
            {}


            //Register receiver for determining screen off and if user is present
            mReceiver = LockScreenStateReceiver()
            val filter = IntentFilter(Intent.ACTION_SCREEN_OFF)
            filter.addAction(Intent.ACTION_USER_PRESENT)

            registerReceiver(mReceiver, filter)
        }
        catch (ex:Exception)
        {

        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
         return START_STICKY
       }

    inner class LockScreenStateReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            try {
                if (intent.action == Intent.ACTION_SCREEN_OFF) {
                    //if screen is turn off show the textview
                    if (!isShowing) {
                        windowManager.addView(myview, params)
                        isShowing = true
                    }
                } else if (intent.action == Intent.ACTION_USER_PRESENT) {
                    //Handle resuming events if user is present/screen is unlocked remove the textview immediately
                    if (isShowing) {
                        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
                            //windowManager.removeViewImmediate(myview)
                        }
                        isShowing = false
                    }
                }
            }
            catch (ex:Exception){

            }
        }

    }

    override fun onDestroy() {
        //unregister receiver when the service is destroy
        try {
            EventBus.getDefault().unregister(this)
            if (mReceiver != null) {
                unregisterReceiver(mReceiver)
            }

            //remove view if it is showing and the service is destroy
            if (isShowing) {
                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
                    //windowManager.removeViewImmediate(myview)
                }
                isShowing = false
            }
        }
        catch (ex:Exception)
        {

        }
        super.onDestroy()
    }

}
like image 380
Mr. Patel Avatar asked Aug 01 '19 04:08

Mr. Patel


1 Answers

I really appreciate answer from @Emir however code he provided was not running in some devices and activity was not launching over the lock screen

Window window = getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
            | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

here problem was the 'OR' part of code was causing issues with some devices so to solve this what i did was instead of calling window flag inside the 'OR' part i called all of those flag individually here is what i did in my oncreate to solve this.

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_lock_screen)
   //execute all flags individually to solve this issue
     window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD)
        window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        val mUIFlag = ( View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_VISIBLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_IMMERSIVE
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)

        window.decorView.systemUiVisibility = mUIFlag

        }
like image 171
Mr. Patel Avatar answered Nov 07 '22 09:11

Mr. Patel