Skip to content

Commit

Permalink
Only start when the shutter button is clicked and show notification t…
Browse files Browse the repository at this point in the history
…imer
  • Loading branch information
kylecorry31 committed Oct 19, 2024
1 parent 9e0f9dd commit e31e4ea
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,67 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.provider.Settings
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.kylecorry.andromeda.notify.Notify
import com.kylecorry.andromeda.preferences.SharedPreferences
import com.kylecorry.intervalometer.R
import com.kylecorry.intervalometer.ui.MainActivity
import com.kylecorry.luna.timer.CoroutineTimer

class IntervalometerService : AccessibilityService() {

private val prefs by lazy { SharedPreferences(this) }
private val knownShutterButtons = listOf(
"com.android.camera:id/shutter_button",
"com.android.camera2:id/shutter_button",
"com.google.android.GoogleCamera:id/shutter_button"
)

private var stopReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
disableSelf()
} else {
// Open accessibility settings
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
}

timer.stop()
Notify.cancel(this@IntervalometerService, 2)
}
}

private var secondsUntilNextPhoto = 0L

private val timer = CoroutineTimer {
clickShutterButton()
// Trigger a notification with the remaining time
secondsUntilNextPhoto--
Notify.cancel(this, 2)
Notify.send(
this,
2,
Notify.alert(
this,
"intervalometer",
secondsUntilNextPhoto.toString(),
null,
R.drawable.bubble,
group = "alerts"
)
)
if (secondsUntilNextPhoto <= 0) {
Notify.cancel(this, 2)
clickShutterButton()
secondsUntilNextPhoto = prefs.getLong("interval") ?: 0
}
}

override fun onAccessibilityEvent(event: AccessibilityEvent?) {
println(event?.packageName)
// Start the timer when a shutter button is clicked
if (!timer.isRunning() && knownShutterButtons.contains(
event?.source?.viewIdResourceName ?: ""
)
) {
restartTimer()
}
}

override fun onInterrupt() {
println("Interrupted")
// Do nothing
}

@SuppressLint("UnspecifiedRegisterReceiverFlag")
Expand All @@ -58,61 +85,51 @@ class IntervalometerService : AccessibilityService() {
registerReceiver(stopReceiver, IntentFilter("com.kylecorry.intervalometer.STOP"))
}

val stopIntent = Intent("com.kylecorry.intervalometer.STOP")
val stopPendingIntent = PendingIntent.getBroadcast(
this,
0,
stopIntent,
PendingIntent.FLAG_IMMUTABLE
)

Notify.send(
this,
1,
Notify.persistent(
this, "intervalometer", "Intervalometer", null, R.drawable.bubble,
actions = listOf(
Notify.action("Stop", stopPendingIntent, R.drawable.ic_info),
Notify.action(
"Stop", PendingIntent.getBroadcast(
this,
0,
Intent("com.kylecorry.intervalometer.STOP"),
PendingIntent.FLAG_IMMUTABLE
), R.drawable.ic_info
),
),
intent = PendingIntent.getActivity(
this,
0,
Intent(this, MainActivity::class.java),
PendingIntent.FLAG_IMMUTABLE
)
),
)

restartTimer()

prefs.onChange.subscribe(this::onPrefsChanged)
}

override fun onDestroy() {
super.onDestroy()
timer.stop()
Notify.cancel(this, 1)
Notify.cancel(this, 2)
unregisterReceiver(stopReceiver)
prefs.onChange.unsubscribe(this::onPrefsChanged)
}

private fun onPrefsChanged(key: String): Boolean {
if (key == "interval") {
restartTimer()
}
return true
}

private fun restartTimer() {
val interval = prefs.getLong("interval") ?: 0
Notify.cancel(this, 2)
if (interval > 0) {
timer.interval(interval * 1000)
secondsUntilNextPhoto = prefs.getLong("interval") ?: 0
timer.interval(1000)
} else {
timer.stop()
}
}

private fun clickShutterButton() {
val knownShutterButtons = listOf(
"com.android.camera:id/shutter_button",
"com.android.camera2:id/shutter_button",
"com.google.android.GoogleCamera:id/shutter_button"
)

val nodeInfo = rootInActiveWindow
for (shutterButton in knownShutterButtons) {
val nodes = nodeInfo?.findAccessibilityNodeInfosByViewId(shutterButton)
Expand All @@ -123,5 +140,8 @@ class IntervalometerService : AccessibilityService() {
return
}
}

// If it got this far, no shutter button was found, so stop the timer
timer.stop()
}
}
3 changes: 2 additions & 1 deletion app/src/main/res/xml/accessibility_service_config.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:accessibilityEventTypes="typeViewClicked"
android:accessibilityFlags="flagReportViewIds|flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="100"
Expand Down

0 comments on commit e31e4ea

Please sign in to comment.