web-dev-qa-db-ja.com

OreoとPieを実行しているデバイスでレイアウトをロック画面にオーバーレイする方法

私のアプリケーションでは、サービスを実行しているときにレイアウトをサービスでオーバーレイしようとしていますが、ターゲットデバイスがoreoよりも低いがバージョンから同じものをオーバーレイしようとすると、サービスが正常に実行され、ロック画面にレイアウトが表示されますオレオより後は機能しませんが、他の回答で提案されているようにフラグをType_Application_Overlayに変更すると、画面がロック解除されたときにレイアウトが表示されますが、ロック画面に表示したいのですが、たくさん検索してみましたが、役立つ回答が見つかりませんでしたこの問題を解決するいくつかの答えは、ロック画面にアクティビティを表示することを提案しました私もそれを試しましたが、それでも役に立ちませんでした!

さらに、アドオンにはPlayストアにいくつかのアプリがあり、oreoやpieでもロック画面にレイアウトを簡単に表示できます。

あなたはこのアプリを見てみることができます:

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

このアプリは、オーバーレイの許可やデバイスの管理者の許可を求めなくても、ロック画面上にカスタムの全画面レイアウトを簡単に表示できます。

このアプリがロック画面の上にオーバーレイできる場合、なぜ同じことができないのですか?

これに関するヘルプや提案は本当にありがたいです!

ロック画面の現在のサービスコードは次のとおりです。

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

}
6
Mr. Patel

私はVOIPに取り組んでいました。基本的に、アプリがリモート通知を受信したときに、IncomingCallActivityを起動して、ユーザーに着信があることを警告しました。オーバーレイやスリープ解除のアクセス許可は必要ありませんでした。

ロック画面オーバーレイのアクティビティを作成し、サービスからアクティビティを開始するだけです。関連する WindowManager フラグをアクティビティの Window on onCreateメソッドに追加します。

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

私はオレオでテストしましたが、問題なく動作します。

1
Emir