Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
567 views
in Technique[技术] by (71.8m points)

screen capture - Android 10: android:foregroundServiceType="mediaProjection" not working with service

Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

I am trying to capture the screen using MediaProjection API but my app is continuously crashing. I tried and giving this error:

   java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

My service code:

  class RecordService : Service() {
        private var mServiceHandler: ServiceHandler? = null
        private var mMediaProjection: MediaProjection? = null
        private var mVirtualDisplay: VirtualDisplay? = null
        private var mMediaRecorder: MediaRecorder? = null
        private var resultCode = 0
        private var data: Intent? = null
        private var mScreenStateReceiver: BroadcastReceiver? = null
    var isInitialized=false
    
        private inner class ServiceHandler(looper: Looper?) : Handler(looper) {
            override fun handleMessage(msg: Message?) {
                if (resultCode == RESULT_OK) {
                    startRecording(resultCode, data)
                } else {
                }
            }
        }
    
        override fun onCreate() {

            // when the main app is being closed
            val notificationIntent = Intent(this, RecordService::class.java)
            val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
            val notification: Notification = Notification.Builder(this)
                .setContentTitle("DataRecorder")
                .setContentText("Your screen is being recorded and saved to your phone.")
                .setSmallIcon(R.drawable.ic_dialog_alert)
                .setContentIntent(pendingIntent)
                .setTicker("Tickertext")
                .build()
            isInitialized=true
            startForeground(ONGOING_NOTIFICATION_ID, notification)
  
            mScreenStateReceiver = MyBroadcastReceiver()
            val screenStateFilter = IntentFilter()
            screenStateFilter.addAction(Intent.ACTION_SCREEN_ON)
            screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF)
            screenStateFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED)
            registerReceiver(mScreenStateReceiver, screenStateFilter)
            val thread = HandlerThread(
                "ServiceStartArguments",
                THREAD_PRIORITY_BACKGROUND
            )
            thread.start()
            val mServiceLooper = thread.looper
            mServiceHandler = ServiceHandler(mServiceLooper)
        }
    
        override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
            Toast.makeText(this, "Starting recording service", Toast.LENGTH_SHORT).show()
            resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, 0)
            data = intent.getParcelableExtra(EXTRA_DATA)
            check(!(resultCode == 0 || data == null)) { "Result code or data missing." }
            val msg = mServiceHandler!!.obtainMessage()
            msg.arg1 = startId
            mServiceHandler!!.sendMessage(msg)
            return START_REDELIVER_INTENT
        }
    
        private fun startRecording(resultCode: Int, data: Intent?) {
            val mProjectionManager =
                applicationContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
            mMediaRecorder = MediaRecorder()
            val metrics = DisplayMetrics()
            val wm =
                applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.defaultDisplay.getRealMetrics(metrics)
            val mScreenDensity = metrics.densityDpi
            val displayWidth = metrics.widthPixels
            val displayHeight = metrics.heightPixels
            mMediaRecorder!!.setVideoSource(MediaRecorder.VideoSource.SURFACE)
            mMediaRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            mMediaRecorder!!.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            mMediaRecorder!!.setVideoEncodingBitRate(8 * 1000 * 1000)
            mMediaRecorder!!.setVideoFrameRate(15)
            mMediaRecorder!!.setVideoSize(displayWidth, displayHeight)
            val videoDir =
                Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES)
                    .absolutePath
            val timestamp = System.currentTimeMillis()
            var orientation = "portrait"
            if (displayWidth > displayHeight) {
                orientation = "landscape"
            }
            val filePathAndName =
                videoDir + "/time_" + timestamp.toString() + "_mode_" + orientation + ".mp4"
            mMediaRecorder!!.setOutputFile(filePathAndName)
            try {
                mMediaRecorder!!.prepare()
            } catch (e: IllegalStateException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            if(isInitialized){
                mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data!!)
                val surface: Surface = mMediaRecorder!!.surface
                mVirtualDisplay = mMediaProjection!!.createVirtualDisplay(
                    "MainActivity",
                    displayWidth,
                    displayHeight,
                    mScreenDensity,
                    VIRTUAL_DISPLAY_FLAG_PRESENTATION,
                    surface,
                    null,
                    null
                )
                mMediaRecorder!!.start()
                Log.v(TAG, "Started recording")
    
            }
           }
    
        companion object {
            private const val TAG = "RECORDERSERVICE"
            private const val EXTRA_RESULT_CODE = "resultcode"
            private const val EXTRA_DATA = "data"
            private const val ONGOING_NOTIFICATION_ID = 23
  
        }
    }

I did add android:foregroundServiceType="mediaProjection" in Manifest as well but it is not working. I tried other similar questing but the issue is not resolved yet. Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

are you adding this to your app manifest ?

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...