8

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()
    }

}
Mr. Patel
  • 1,379
  • 8
  • 21

2 Answers2

9

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

        }
Mr. Patel
  • 1,379
  • 8
  • 21
  • I put this code in splash its not showing i lockscreen .In which activity we suppose to put windows flag code – Android Geek Apr 09 '20 at 07:58
  • @AndroidGeek you need to put it inside the oncreate of the activity which is intended for showing over lock screen just follow the activity life cycle and it should work however in some devices still there are a bit of problems but it's really rare! – Mr. Patel Apr 10 '20 at 08:13
  • actually I have made my overlay view in service only but just to remove this depreciated flags now I suppose to make one transparent activity which will show my view..anyways ..Thanks! – Android Geek Apr 11 '20 at 08:59
2

I was working on VOIP, basically what I did was when the app receives a remote notification, it launches my IncomingCallActivity to alert the user there is an incoming call. It did not require overlay or wake lock permissions.

All you need to do is create an Activity for your lock screen overlay, start the activity from your service. Add related WindowManager flags to your activity's Window on onCreate method.

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

I tested on Oreo and it works fine.

Emir
  • 279
  • 2
  • 8
  • 2
    Doesn't work as expected when i use these flags they are shown only in some devices moreover in some devices having pie it's not working however when i run same code in samsung tab it working without any issues – Mr. Patel Aug 06 '19 at 10:46
  • Can you tell me models of devices you know that does not work – Emir Aug 06 '19 at 10:52
  • yes sure some of them are samsung j2,itel I5503(Pie) – Mr. Patel Aug 06 '19 at 11:04
  • this code is majorly not working on most of devices however when i run it on samsung tab it's working without any issues Model(SM-T285YD). – Mr. Patel Aug 06 '19 at 11:05
  • Did you test https://play.google.com/store/apps/details?id=com.wifihacker.whousemywifi.wifirouter.wifisecurity this app on samsung j2 & itel I5593 – Emir Aug 06 '19 at 11:08
  • Yes i did and it was working smoothly without any problems – Mr. Patel Aug 06 '19 at 11:10
  • To make to more clear here activity is launched but instead of being shown on lockscreen it's being launched in application. – Mr. Patel Aug 06 '19 at 11:29
  • It worked on Huawei Y6 Android P. My service is a foreground service, I don't know if that makes a difference. Samsung J4 Android 8 works well too. So you are saying that activity is being launched (Seen on logcat) but not displaying on lockscreen. – Emir Aug 06 '19 at 11:49
  • Yes exactly the activity is being launched from service but instead of being shown on lockscreen it's getting shown inside the application – Mr. Patel Aug 06 '19 at 11:53
  • So far i succeeded with samsung tab only where activity is being showed properly over lock screen – Mr. Patel Aug 06 '19 at 11:54
  • what is your targetSDK ? I am testing on 26, might be related to this. I will update when I test on 28 – Emir Aug 06 '19 at 18:08
  • My target sdk is 28 and min is 16 – Mr. Patel Aug 07 '19 at 03:21
  • If your code is working in your perspective you can share it's github link i'll take a look if i'm missing something! – Mr. Patel Aug 07 '19 at 03:22
  • Thanks your suggestion helped a lot however i did some changes in the code you provided and now activity is successfully launching over lock screen in all type of devices without any problems!!! – Mr. Patel Aug 09 '19 at 09:08
  • Glad you got it working. What was the problem though? – Emir Aug 09 '19 at 09:30
  • Wait i'll post an answer here to what i did to solve this problem! – Mr. Patel Aug 09 '19 at 09:36