summaryrefslogtreecommitdiffstats
path: root/android/app/src/main/java/eu
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src/main/java/eu')
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/MainActivity.kt74
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/MainWorkerService.kt169
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/StartReceiver.kt16
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Color.kt11
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Theme.kt58
-rw-r--r--android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Type.kt34
6 files changed, 362 insertions, 0 deletions
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/MainActivity.kt b/android/app/src/main/java/eu/jopek/dingdongmail/MainActivity.kt
new file mode 100644
index 0000000..a13b0d2
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/MainActivity.kt
@@ -0,0 +1,74 @@
+package eu.jopek.dingdongmail
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import eu.jopek.dingdongmail.ui.theme.DingDongMailTheme
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ DingDongMailTheme {
+ Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
+ Greeting(
+ modifier = Modifier.padding(innerPadding)
+ ) {
+ actionOnService(it)
+ }
+ }
+ }
+ }
+
+ log("Starting the service from MainActivity.onCreate")
+ Intent(this, MainWorkerService::class.java).also {
+ it.action = Actions.START.name
+ startForegroundService(it)
+ }
+ }
+
+ private fun actionOnService(action: Actions) {
+ log("Starting the service from button")
+ Intent(this, MainWorkerService::class.java).also {
+ it.action = action.name
+ if (action == Actions.STOP) stopService(it)
+ else startForegroundService(it)
+ }
+ }
+}
+
+@Composable
+fun Greeting(modifier: Modifier = Modifier, onClick: (Actions) -> Unit) {
+ Column {
+ Text(
+ text = "Ding-Dong Mail!",
+ modifier = modifier
+ )
+ Button(onClick = { onClick(Actions.START) }) {
+ Text(text = "Start")
+ }
+ Button(onClick = { onClick(Actions.STOP) }) {
+ Text(text = "Stop")
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun GreetingPreview() {
+ DingDongMailTheme {
+ Greeting() {}
+ }
+} \ No newline at end of file
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/MainWorkerService.kt b/android/app/src/main/java/eu/jopek/dingdongmail/MainWorkerService.kt
new file mode 100644
index 0000000..4991c3a
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/MainWorkerService.kt
@@ -0,0 +1,169 @@
+package eu.jopek.dingdongmail
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
+import android.content.pm.ServiceInfo
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Build
+import android.os.IBinder
+import android.os.PowerManager
+import android.util.Log
+import android.widget.Toast
+import eu.jopek.dingdongmail.ui.theme.DingDongMailTheme
+
+fun log(str: String) {
+ if (BuildConfig.DEBUG) {
+ Log.d("Ding-Dong Mail", str)
+ }
+}
+
+enum class Actions {
+ START,
+ STOP
+}
+
+class MainWorkerService : Service() {
+ private var wakeLock: PowerManager.WakeLock? = null
+ private var isServiceStarted = false
+
+ override fun onBind(intent: Intent): IBinder? {
+ log("Some component want to bind with the service")
+ // We don't provide binding, so return null
+ return null
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ if (intent != null) {
+ val action = intent.action
+ log("using an intent with action $action")
+ when (action) {
+ Actions.START.name -> startService()
+ Actions.STOP.name -> stopService()
+ else -> log("This should never happen. No action in the received intent")
+ }
+ } else {
+ log("with a null intent. It has been probably restarted by the system.")
+ }
+ // by returning this we make sure the service is restarted if the system kills the service
+ return START_STICKY
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ log("The service has been created")
+ val notification = createNotification()
+ startForeground(ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE, notification)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ log("The service has been destroyed")
+ Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show()
+ }
+
+ private fun startService() {
+ if (isServiceStarted) return
+ log("Starting the foreground service task")
+ Toast.makeText(this, "Service starting its task", Toast.LENGTH_SHORT).show()
+ isServiceStarted = true
+
+ // we need this lock so our service gets not affected by Doze Mode
+ wakeLock =
+ (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
+ newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DingDongMail::lock").apply {
+ acquire()
+ }
+ }
+
+ val i = Intent("eu.faircode.email.DISABLE").apply {
+ setPackage("eu.faircode.email")
+ }
+ startService(i)
+ val intentFilter = IntentFilter("io.heckel.ntfy.MESSAGE_RECEIVED")
+ registerReceiver(receiver, intentFilter, RECEIVER_EXPORTED)
+ }
+
+ private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val msg = intent.getStringExtra("message") ?: return
+ val (email, _mailbox) = msg.split(":", ignoreCase = false, limit = 2)
+ log("email: $email")
+ val i = Intent("eu.faircode.email.POLL").apply {
+ setPackage("eu.faircode.email")
+ putExtra("account", email)
+ }
+ startService(i)
+ }
+ }
+
+ private fun stopService() {
+ log("Stopping the foreground service")
+ Toast.makeText(this, "Service stopping", Toast.LENGTH_SHORT).show()
+ val i = Intent("eu.faircode.email.ENABLE").apply {
+ setPackage("eu.faircode.email")
+ }
+ startService(i)
+ wakeLock?.let {
+ if (it.isHeld) {
+ it.release()
+ }
+ }
+ stopSelf()
+ unregisterReceiver(receiver)
+ isServiceStarted = false
+ }
+
+ private fun createNotification(): Notification {
+ val notificationChannelId = "DING-DONG MAIL - FOREGROUND SERVICE"
+
+ val notificationManager =
+ getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ val channel = NotificationChannel(
+ notificationChannelId,
+ "Foreground service",
+ NotificationManager.IMPORTANCE_MIN
+ ).let {
+ it.description = "Foreground service"
+ it.enableLights(true)
+ it.lightColor = Color.RED
+ it.enableVibration(true)
+ it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
+ it
+ }
+ notificationManager.createNotificationChannel(channel)
+
+ val pendingIntent: PendingIntent =
+ Intent(this, MainActivity::class.java).let { notificationIntent ->
+ PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ val builder: Notification.Builder =
+ Notification.Builder(
+ this,
+ notificationChannelId
+ )
+
+ return builder
+ .setContentTitle("Ding-Dong Mail - Foreground Service")
+ .setContentText("This makes Ding-Dong Mail works so good")
+ .setContentIntent(pendingIntent)
+ .setSmallIcon(R.drawable.notification)
+ .setColor(resources.getColor(R.color.notification_bg, theme))
+ .setLargeIcon(
+ BitmapFactory.decodeResource(
+ applicationContext.resources,
+ R.mipmap.logo
+ )
+ )
+ .build()
+ }
+} \ No newline at end of file
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/StartReceiver.kt b/android/app/src/main/java/eu/jopek/dingdongmail/StartReceiver.kt
new file mode 100644
index 0000000..e5fad0b
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/StartReceiver.kt
@@ -0,0 +1,16 @@
+package eu.jopek.dingdongmail
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class StartReceiver: BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ log("Starting the service from a StartReceiver")
+ Intent(context, MainWorkerService::class.java).also {
+ it.action = Actions.START.name
+ context.startForegroundService(it)
+ }
+ }
+
+} \ No newline at end of file
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Color.kt b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Color.kt
new file mode 100644
index 0000000..fdb4075
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package eu.jopek.dingdongmail.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260) \ No newline at end of file
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Theme.kt b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Theme.kt
new file mode 100644
index 0000000..444f356
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Theme.kt
@@ -0,0 +1,58 @@
+package eu.jopek.dingdongmail.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun DingDongMailTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+} \ No newline at end of file
diff --git a/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Type.kt b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Type.kt
new file mode 100644
index 0000000..03d0dd1
--- /dev/null
+++ b/android/app/src/main/java/eu/jopek/dingdongmail/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package eu.jopek.dingdongmail.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+) \ No newline at end of file