Skip to content
This repository has been archived by the owner on Dec 31, 2024. It is now read-only.

Commit

Permalink
サービスの定義にandroid:stopWithTask="false"属性を追加。
Browse files Browse the repository at this point in the history
設定画面に"録画停止"ボタンを追加。
設定画面にサービスの起動状態を表示する。
設定画面にサービスが停止した理由を表示する。
onTaskRemoved発生時にstopSelfを呼ばない。またAlarm経由で少し後にサービスを開始しなおす。
上に関連して、サービス開始時のIntentにMediaProjection作成に必要な情報を保持する。
PendingIntent用のrequestCodeの値が重複していたバグを修正。
getVolumePathApi21() の軽微なバグを修正。
画面サイズ取得時にWindowManager.defaultDisplayではなくDisplayManager.getDisplayを使う。
  • Loading branch information
tateisu committed Dec 29, 2019
1 parent e36a532 commit 4346d33
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 269 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@
<service
android:name=".CaptureServiceStill"
android:exported="false"
android:stopWithTask="false"
android:foregroundServiceType="mediaProjection"
tools:targetApi="q" />

<service
android:name=".CaptureServiceVideo"
android:exported="false"
android:stopWithTask="false"
android:foregroundServiceType="mediaProjection"
tools:targetApi="q" />

Expand Down
110 changes: 88 additions & 22 deletions app/src/main/java/jp/juggler/screenshotbutton/ActMain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,21 @@ class ActMain : AppCompatActivity(), View.OnClickListener {

private lateinit var btnStartStopStill: Button
private lateinit var btnStartStopVideo: Button
private lateinit var btnStopRecording: Button
private lateinit var tvButtonSizeError: TextView
private lateinit var tvSaveFolder: TextView
private lateinit var tvCodec: TextView
private lateinit var tvStatusStill: TextView
private lateinit var tvStatusVideo: TextView

private var timeStartButtonTappedStill = 0L
private var timeStartButtonTappedVideo = 0L

override fun onCreate(savedInstanceState: Bundle?) {
App1.prepareAppState(this)
log.d("onCreate savedInstanceState=$savedInstanceState")
refActivity = WeakReference(this)
super.onCreate(savedInstanceState)
App1.prepareAppState(this)
initUI()
}

Expand Down Expand Up @@ -98,11 +101,14 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
openSaveTreeUriChooser()

R.id.btnStartStopStill ->
if (CaptureServiceStill.isAlive()) {
stopService(Intent(this, CaptureServiceStill::class.java))
} else {
timeStartButtonTappedStill = SystemClock.elapsedRealtime()
dispatch()
when (val service = CaptureServiceStill.getService()) {
null -> {
timeStartButtonTappedStill = SystemClock.elapsedRealtime()
dispatch()
}
else -> {
service.stopWithReason("StopButton")
}
}

R.id.btnResetPositionStill -> {
Expand All @@ -114,17 +120,20 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
}

R.id.btnStartStopVideo ->
if (CaptureServiceVideo.isAlive()) {
stopService(Intent(this, CaptureServiceVideo::class.java))
} else {
try {
Capture.loadVideoSetting(this, App1.pref)
} catch (ex: Throwable) {
log.eToast(this, ex, "Video setting error.")
return
when (val service = CaptureServiceVideo.getService()) {
null -> {
try {
Capture.loadVideoSetting(this, App1.pref)
} catch (ex: Throwable) {
log.eToast(this, ex, "Video setting error.")
return
}
timeStartButtonTappedVideo = SystemClock.elapsedRealtime()
dispatch()
}
else -> {
service.stopWithReason("StopButton")
}
timeStartButtonTappedVideo = SystemClock.elapsedRealtime()
dispatch()
}

R.id.btnResetPositionVideo -> {
Expand All @@ -145,6 +154,12 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
}
ad.show(this, getString(R.string.codec))
}

R.id.btnStopRecording ->
CaptureServiceVideo.getService()
.runOnService(this) {
captureStop()
}
}
}

Expand All @@ -160,15 +175,20 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
val screenWidth = dm.widthPixels
val pageWidth = 360f.dp2px(dm)
val remain = max(0, screenWidth - pageWidth)
(findViewById<View>(R.id.svRoot).layoutParams as? ViewGroup.MarginLayoutParams)

findViewById<View>(R.id.svRoot)
.layoutParams
.castOrNull<ViewGroup.MarginLayoutParams>()
?.marginEnd = remain

btnStartStopStill = findViewById(R.id.btnStartStopStill)
btnStartStopVideo = findViewById(R.id.btnStartStopVideo)
btnStopRecording = findViewById(R.id.btnStopRecording)

arrayOf(
btnStartStopStill,
btnStartStopVideo,
btnStopRecording,
findViewById<View>(R.id.btnSaveFolder),
findViewById<View>(R.id.btnResetPositionStill),
findViewById<View>(R.id.btnResetPositionVideo),
Expand All @@ -181,6 +201,8 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
tvButtonSizeError = findViewById(R.id.tvButtonSizeError)
tvButtonSizeError.vg(false)
tvCodec = findViewById(R.id.tvCodec)
tvStatusStill = findViewById(R.id.tvStatusStill)
tvStatusVideo = findViewById(R.id.tvStatusVideo)

val pref = App1.pref

Expand Down Expand Up @@ -223,10 +245,15 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
else -> null
}

val tvVideoError: TextView = findViewById(R.id.tvVideoError)
tvVideoError.vg(message != null)?.text = message
videcCaptureEnabled = message == null

if (!videcCaptureEnabled) {
tvStatusVideo.setTextColor(ContextCompat.getColor(this, R.color.colorTextError))
tvStatusVideo.text = message

btnStopRecording.visibility = View.INVISIBLE
}

val tvLogToFileDesc: TextView = findViewById(R.id.tvLogToFileDesc)
tvLogToFileDesc.text = getString(
R.string.output_log_to_file_desc,
Expand Down Expand Up @@ -280,8 +307,39 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
btnStartStopStill.isEnabledWithColor = !isCapturing

btnStartStopVideo.isEnabledWithColor = !isCapturing && videcCaptureEnabled
}

btnStopRecording.isEnabledWithColor = CaptureServiceBase.isVideoCapturing()

tvStatusStill.text = getString(
R.string.status_is,
when {
CaptureServiceStill.isAlive() ->
getString(R.string.status_running)
else ->
getString(
R.string.stopped_by,
CaptureServiceBase.getStopReason(CaptureServiceStill::class.java)
?: ""
)
}
)

if (videcCaptureEnabled) {
tvStatusVideo.text = getString(
R.string.status_is,
when {
CaptureServiceVideo.isAlive() ->
getString(R.string.status_running)
else ->
getString(
R.string.stopped_by,
CaptureServiceBase.getStopReason(CaptureServiceVideo::class.java)
?: ""
)
}
)
}
}

// 権限のチェックと取得インタラクションの開始
// 画面表示時や撮影ボタンの表示開始時に呼ばれる
Expand All @@ -299,7 +357,11 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
timeStartButtonTappedStill = 0L
ContextCompat.startForegroundService(
this,
Intent(this, CaptureServiceStill::class.java)
Intent(this, CaptureServiceStill::class.java).apply {
Capture.screenCaptureIntent?.let {
putExtra(CaptureServiceBase.EXTRA_SCREEN_CAPTURE_INTENT, it)
}
}
)
}

Expand All @@ -310,7 +372,11 @@ class ActMain : AppCompatActivity(), View.OnClickListener {
timeStartButtonTappedVideo = 0L
ContextCompat.startForegroundService(
this,
Intent(this, CaptureServiceVideo::class.java)
Intent(this, CaptureServiceVideo::class.java).apply {
Capture.screenCaptureIntent?.let {
putExtra(CaptureServiceBase.EXTRA_SCREEN_CAPTURE_INTENT, it)
}
}
)
}
}
Expand Down
18 changes: 7 additions & 11 deletions app/src/main/java/jp/juggler/screenshotbutton/Capture.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import java.util.*
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.math.max
import kotlin.math.min
import android.media.MediaCodec
import android.os.Bundle


object Capture {
Expand All @@ -54,7 +51,7 @@ object Capture {
private lateinit var mediaProjectionManager: MediaProjectionManager
private lateinit var windowManager: WindowManager

private var screenCaptureIntent: Intent? = null
var screenCaptureIntent: Intent? = null
private var mediaProjection: MediaProjection? = null
private var mediaProjectionAddr = AtomicReference<String?>(null)
private var mediaProjectionState = MediaProjectionState.Off
Expand All @@ -66,10 +63,8 @@ object Capture {
fun onInitialize(context: Context) {
log.d("onInitialize")
mediaScannerTracker = MediaScannerTracker(context.applicationContext, handler)
mediaProjectionManager =
context.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
windowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
mediaProjectionManager = systemService(context)!!
windowManager = systemService(context)!!
}

// mediaProjection と screenCaptureIntentを解放する
Expand Down Expand Up @@ -107,23 +102,24 @@ object Capture {
}

fun handleScreenCaptureIntentResult(
activity: Activity,
context:Context,
resultCode: Int,
data: Intent?
): Boolean {
log.d("handleScreenCaptureIntentResult")
return when {
resultCode != Activity.RESULT_OK -> {
log.eToast(activity, false, "permission not granted.")
log.eToast(context, false, "permission not granted.")
release()
}

data == null -> {
log.eToast(activity, false, "result data is null.")
log.eToast(context, false, "result data is null.")
release()
}

else -> {
log.i("screenCaptureIntent set!")
// 得られたインテントはExtrasにBinderProxyオブジェクトを含む。ファイルに保存とかは無理っぽい…
screenCaptureIntent = data
mediaProjectionState = MediaProjectionState.HasScreenCaptureIntent
Expand Down
Loading

0 comments on commit 4346d33

Please sign in to comment.