Compare commits

...

3 Commits

Author SHA1 Message Date
moon
92a24851f1 alert trigger 2026-07-22 10:40:56 +06:30
moon
f1a2707190 setup alert receiver 2026-07-22 00:11:45 +06:30
moon
706a48d1d1 released date added 2026-07-21 23:27:19 +06:30
7 changed files with 248 additions and 4 deletions

View File

@ -8,3 +8,7 @@
* fixed recent transaction only working for top 3
* routed to dashboard after printing receipt
* receipt printing animation re-scale
*
### version 3.4
* disable display always on
* auto-settlement

View File

@ -19,6 +19,7 @@
<uses-permission android:name="com.sunmi.perm.SECURITY" />
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.CAMERA" />
@ -38,6 +39,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MOBPOS">
<receiver android:name=".auto_settlement.AlarmReceiver" android:exported="false"/>
<service android:name=".auto_settlement.AutoSettleService" android:exported="false" android:foregroundServiceType="dataSync" />
<activity
android:name="com.mob.utsmyanmar.MainActivity"
android:exported="true"

View File

@ -1,26 +1,33 @@
package com.mob.utsmyanmar
import android.Manifest
import android.os.Build
import android.os.Bundle
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.compose.rememberNavController
import com.mob.utsmyanmar.auto_settlement.SettlementScheduler
import com.mob.utsmyanmar.ui.navigation.AppNavGraph
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
@RequiresApi(Build.VERSION_CODES.N)
override fun onCreate(savedInstanceState: Bundle?) {
SettlementScheduler.schedule(this)
// installSplashScreen()
super.onCreate(savedInstanceState)
enableEdgeToEdge()
hideSystemBars()
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContent {
MOBPOSTheme {
val navController = rememberNavController()

View File

@ -0,0 +1,26 @@
package com.mob.utsmyanmar.auto_settlement
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.content.ContextCompat
import dagger.hilt.android.AndroidEntryPoint
import sunmi.sunmiui.utils.LogUtil
@AndroidEntryPoint
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val serviceIntent = Intent(context, AutoSettleService::class.java)
LogUtil.d(AlarmReceiver::class.java.simpleName, "Alert service")
if (context != null) {
ContextCompat.startForegroundService(
context,
serviceIntent
)
}
LogUtil.d(AlarmReceiver::class.java.simpleName, "Foreground service")
}
}

View File

@ -0,0 +1,91 @@
package com.mob.utsmyanmar.auto_settlement
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.media.AudioAttributes
import android.media.RingtoneManager
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.mob.utsmyanmar.MainActivity
import com.mob.utsmyanmar.R
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import dagger.hilt.android.AndroidEntryPoint
import sunmi.sunmiui.utils.LogUtil
@AndroidEntryPoint
class AutoSettleService : Service() {
companion object {
const val CHANNEL_ID = "auto_settlement_channel"
const val NOTIFICATION_ID = 1001
}
override fun onCreate() {
super.onCreate()
LogUtil.d(AutoSettleService::class.java.simpleName, "auto settle service called")
startForegroundNotification()
}
@RequiresApi(Build.VERSION_CODES.N)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (!SystemParamsOperation.getInstance().settlementStatus) {
stopSelf()
return START_NOT_STICKY
}
launchSettlement()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
@SuppressLint("ForegroundServiceType")
private fun startForegroundNotification() {
LogUtil.d(AutoSettleService::class.java.simpleName, "foreground noti called")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"AUTO SETTLEMENT",
NotificationManager.IMPORTANCE_HIGH
)
channel.description = "Auto Settlement notification"
channel.enableVibration(true)
channel.setSound(
RingtoneManager.getDefaultUri(
RingtoneManager.TYPE_NOTIFICATION
), AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()
)
val manager = getSystemService(NotificationManager::class.java)
manager?.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.logo_mob)
.setContentTitle("Auto Settlement")
.setContentText("Processing...")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
startForeground(NOTIFICATION_ID, notification)
}
private fun launchSettlement() {
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
)
putExtra("AUTO_SETTLEMENT", true)
}
startActivity(intent)
}
}

View File

@ -0,0 +1,84 @@
package com.mob.utsmyanmar.auto_settlement
import android.Manifest
import android.annotation.SuppressLint
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.annotation.RequiresPermission
import java.util.Calendar
object SettlementScheduler {
@RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
fun schedule(context: Context) {
val calendar = Calendar.getInstance().apply {
// Auto settlement time
set(Calendar.HOUR_OF_DAY, 1)
set(Calendar.MINUTE, 10)
set(Calendar.SECOND, 0)
if (before(Calendar.getInstance())) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE)
as AlarmManager
val intent = Intent(
context,
AlarmReceiver::class.java
)
val pendingIntent = PendingIntent.getBroadcast(
context,
100,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
@SuppressLint("ServiceCast")
fun cancel(context: Context) {
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE)
as AlarmManager
val intent = Intent(
context,
AlarmReceiver::class.java
)
val pendingIntent = PendingIntent.getBroadcast(
context,
100,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.cancel(pendingIntent)
}
}

View File

@ -51,6 +51,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.mob.utsmyanmar.BuildConfig
import com.mob.utsmyanmar.R
import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.device_info.DeviceInfoUiState
@ -97,6 +98,7 @@ fun DashboardScreen2(
fun successMessage(action: String) = "$action success."
fun failureMessage(action: String, resultCode: Int?) =
"$action failed. Response code: ${resultCode ?: -1}"
fun networkFailureMessage(action: String) = "Network error during $action."
fun openHostActionDialog(action: String) {
activeHostAction = action
@ -141,12 +143,14 @@ fun DashboardScreen2(
dialogMessage = successMessage(activeHostAction)
}
}
override fun onFailureSignOn(resultCode: Int?) {
mainHandler.post {
isHostActionRunning = false
dialogMessage = failureMessage(activeHostAction, resultCode)
}
}
override fun onNetworkFailSignOn(message: String?) {
mainHandler.post {
isHostActionRunning = false
@ -253,6 +257,21 @@ fun DashboardScreen2(
}
}
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = "App Version : ${BuildConfig.VERSION_NAME}",
style = MaterialTheme.typography.bodySmall,
color = Color.Gray,
modifier = Modifier.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(10.dp))
Text(
text = "Released on : 21-Jul-26",
style = MaterialTheme.typography.bodySmall,
color = Color.Gray,
modifier = Modifier.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(10.dp))
Text(
@ -341,6 +360,16 @@ fun DashboardScreen2(
},
trailingIcon = {},
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "v${BuildConfig.VERSION_NAME}",
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
style = MaterialTheme.typography.labelSmall,
color = Color.Black.copy(alpha = 0.5f)
)
}
}
) {