blob: 30509e23d18615989fff3c826a2e96924b56a358 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.screenrecord
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.ResultReceiver
import android.os.UserHandle
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.Switch
import androidx.annotation.LayoutRes
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.media.MediaProjectionAppSelectorActivity
import com.android.systemui.media.MediaProjectionCaptureTarget
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserContextProvider
/** Dialog to select screen recording options */
class ScreenRecordPermissionDialog(
context: Context?,
private val hostUserHandle: UserHandle,
private val controller: RecordingController,
private val activityStarter: ActivityStarter,
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val userContextProvider: UserContextProvider,
private val onStartRecordingClicked: Runnable?
) :
BaseScreenSharePermissionDialog(
context,
createOptionList(),
null,
R.drawable.ic_screenrecord,
R.color.screenrecord_icon_color
) {
private lateinit var tapsSwitch: Switch
private lateinit var tapsView: View
private lateinit var audioSwitch: Switch
private lateinit var options: Spinner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setDialogTitle(R.string.screenrecord_start_label)
setStartButtonText(R.string.screenrecord_start_recording)
setStartButtonOnClickListener { v: View? ->
onStartRecordingClicked?.run()
if (selectedScreenShareOption.mode == ENTIRE_SCREEN) {
requestScreenCapture(/* captureTarget= */ null)
}
if (selectedScreenShareOption.mode == SINGLE_APP) {
val intent = Intent(context, MediaProjectionAppSelectorActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// We can't start activity for result here so we use result receiver to get
// the selected target to capture
intent.putExtra(
MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
CaptureTargetResultReceiver()
)
intent.putExtra(
MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE,
hostUserHandle
)
val animationController = dialogLaunchAnimator.createActivityLaunchController(v!!)
if (animationController == null) {
dismiss()
}
activityStarter.startActivity(intent, /* dismissShade= */ true, animationController)
}
dismiss()
}
initRecordOptionsView()
}
@LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options
private fun initRecordOptionsView() {
audioSwitch = findViewById(R.id.screenrecord_audio_switch)
tapsSwitch = findViewById(R.id.screenrecord_taps_switch)
tapsView = findViewById(R.id.show_taps)
updateTapsViewVisibility()
options = findViewById(R.id.screen_recording_options)
val a: ArrayAdapter<*> =
ScreenRecordingAdapter(context, android.R.layout.simple_spinner_dropdown_item, MODES)
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
options.adapter = a
options.setOnItemClickListenerInt { _: AdapterView<*>?, _: View?, _: Int, _: Long ->
audioSwitch.isChecked = true
}
}
override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) {
super.onItemSelected(adapterView, view, pos, id)
updateTapsViewVisibility()
}
private fun updateTapsViewVisibility() {
tapsView.visibility = if (selectedScreenShareOption.mode == SINGLE_APP) GONE else VISIBLE
}
/**
* Starts screen capture after some countdown
*
* @param captureTarget target to capture (could be e.g. a task) or null to record the whole
* screen
*/
private fun requestScreenCapture(captureTarget: MediaProjectionCaptureTarget?) {
val userContext = userContextProvider.userContext
val showTaps = selectedScreenShareOption.mode != SINGLE_APP && tapsSwitch.isChecked
val audioMode =
if (audioSwitch.isChecked) options.selectedItem as ScreenRecordingAudioSource
else ScreenRecordingAudioSource.NONE
val startIntent =
PendingIntent.getForegroundService(
userContext,
RecordingService.REQUEST_CODE,
RecordingService.getStartIntent(
userContext,
Activity.RESULT_OK,
audioMode.ordinal,
showTaps,
captureTarget
),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val stopIntent =
PendingIntent.getService(
userContext,
RecordingService.REQUEST_CODE,
RecordingService.getStopIntent(userContext),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
controller.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent)
}
private inner class CaptureTargetResultReceiver() :
ResultReceiver(Handler(Looper.getMainLooper())) {
override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
if (resultCode == Activity.RESULT_OK) {
val captureTarget =
resultData.getParcelable(
MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET,
MediaProjectionCaptureTarget::class.java
)
// Start recording of the selected target
requestScreenCapture(captureTarget)
}
}
}
companion object {
private val MODES =
listOf(
ScreenRecordingAudioSource.INTERNAL,
ScreenRecordingAudioSource.MIC,
ScreenRecordingAudioSource.MIC_AND_INTERNAL
)
private const val DELAY_MS: Long = 3000
private const val INTERVAL_MS: Long = 1000
private fun createOptionList(): List<ScreenShareOption> {
return listOf(
ScreenShareOption(
ENTIRE_SCREEN,
R.string.screenrecord_option_entire_screen,
R.string.screenrecord_warning_entire_screen
),
ScreenShareOption(
SINGLE_APP,
R.string.screenrecord_option_single_app,
R.string.screenrecord_warning_single_app
)
)
}
}
}