Android Question Issue with an app/service sending email/sms at midnight

imbault

Well-Known Member
Licensed User
Longtime User
Hi Everyone,


I've developped a small app which has an activity layouts, but also launches a service (which runs if the mobile reboots), the purpose of the service is to send all the days at midnight some informations entered in the app: no pb with that.
So at 00:00, the service will send an eMail via SMTP and a SMS (to an address and a mobile number entered in a parameter screen).

This app and service works on my main mobile (samsung S4) and a collegue mobile (samsung S4) without any pb.

By the way, I deployed this app only sending the APK file by email, no play store.

But for the person who is supposed to really use this app, nothing is send at midnight. So I add a button to to that send duty which works for him. But The service, not at all, I must to add that his mobile is on silent mode at midnight (not airplane mode, lol).

So maybe, someone did face the same pb

Many thanks.

Patrick
 

lemonisdead

Well-Known Member
Licensed User
Longtime User
Hello Patrick,

On some devices the battery economy plan puts the mobile in deep sleep. On those mobiles planned services won't wake even when set to true in StartServiceAt.

Did you already tried to change the PhoneWakeState ? Or perhaps on the user's mobile the service gets killed (try to use a sticky service)
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Must your app send the information at 12:00 am? Or can it send it once a day?
Hi Erel,
12:00 is not mandatory, once a day yes, in order to send the operations of the day before

Ths question is why does it works very well on my phone and not my client phone
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Hello Patrick,

On some devices the battery economy plan puts the mobile in deep sleep. On those mobiles planned services won't wake even when set to true in StartServiceAt.

Did you already tried to change the PhoneWakeState ? Or perhaps on the user's mobile the service gets killed (try to use a sticky service)

Hi, no I didn't, where do I put this settings, in the service ?
Service is only called by the Activity by StartService(ndf2sms)
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Have you got the following lines on top of your service module?
B4X:
'Try these 2 lines
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY

Does your phone read any kind of data from the internet?
 
Last edited:
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Have you got the following lines on top of your service module?
B4X:
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY

Does your phone read any kind of data from the internet?

StartAtBoot Yes, but not the other one, will it fix the pb?
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
I do thank you @Erel.
@imbault (and the others) :
Here are the results of my modest research. Most manufacturers for whom the power saving plan blocks the execution of the services (if PhoneWakeState does not maintain the wanted state), use specific LockScreen app.
Another solution I found, is then to provide my own LockScreen by following this excellent tutorial https://www.b4x.com/android/forum/threads/43327/#content
In any case, I often solve my problems by providing my own LockScreen which maintains the PhoneWakeState when the screen goes in the off state (the light).
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
but it's only an app, not a lockscreen app...
I had understood : I mean, if you can't manage to have the device not entering the deep sleep mode, you could try to replace the LockScreen by your own which will manage the PhoneWakeState
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Ok @lemonisdead, but I'm thinking another solution, changing lockscreen app of my client is a pretty big change, but anyway, I appreciate your help
Thx

Patrick
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Hmm, are you doing the following after the service has first started?

B4X:
    StartServiceAt(Me, MidNightTime, True)
No, in the Activity I run
B4X:
    StartService(ndf2sms)

Then in the Service, I've a timer which calls a sub each second, this sub checks if the day has changed to day+1 (midnight), if so I send sms and email.

On my Galasy S4, no pb at all....
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hmm, I've personally found that relying on timers in the service module was not really that reliable. I switched to StartServiceAt(Null, TimeToNextMinute, True) and all my troubles went away. I would personally use StartServiceAt(Null, TimeToNextMinute, True) in the service and then check the time every time the service restarts which is every sixty seconds.

PLEASE NOTE:
Timer not necessary. I've not tested this service code, but I hope that it works for you.
B4X:
#Region Service Attributes
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

'SERVICE START
Sub Service_Start(StartingIntent As Intent)
    StartServiceAt(Null, TimeToNextMinute, True) 'Service will restart every minute
    CallSub(Null, IsItMidnight)
End Sub

'TIME TO NEXT WHOLE MINUTE
Sub TimeToNextMinute As Long
    Dim NextMin As Long
        NextMin = DateTime.Now + DateTime.TicksPerMinute
        NextMin = NextMin - (NextMin Mod DateTime.TicksPerMinute)
    Return NextMin
End Sub

'CHECK THE TIME TO SEE IF IT'S MIDNIGHT
Sub IsItMidnight
    DateTime.TimeFormat = "HH:mm"
    If DateTime.Time(DateTime.Now) = "00:00" Then CallSub(Null, SendEmail)
End Sub

Good luck...
 
Last edited:
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Hi @Peter Simpson , thank you very much for your code and your efforts, but not yet. last night, my app runs well for the 1st time for my client, so I'm crossing my finger.
Else, I'll try your way.

My best regards

Patrick
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Hmm, I've personally found that relying on timers in the service module was not really that reliable. I switched to StartServiceAt(Null, TimeToNextMinute, True) and all my troubles went away. I would personally use StartServiceAt(Null, TimeToNextMinute, True) in the service and then check the time every time the service restarts which is every sixty seconds.

PLEASE NOTE:
Timer not necessary. I've not tested this service code, but I hope that it works for you.
B4X:
#Region Service Attributes
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

'SERVICE START
Sub Service_Start(StartingIntent As Intent)
    StartServiceAt(Null, TimeToNextMinute, True) 'Service will restart every minute
    CallSub(Null, IsItMidnight)
End Sub

'TIME TO NEXT WHOLE MINUTE
Sub TimeToNextMinute As Long
    Dim NextMin As Long
        NextMin = DateTime.Now + DateTime.TicksPerMinute
        NextMin = NextMin - (NextMin Mod DateTime.TicksPerMinute)
    Return NextMin
End Sub

'CHECK THE TIME TO SEE IF IT'S MIDNIGHT
Sub IsItMidnight
    DateTime.TimeFormat = "HH:mm"
    If DateTime.Time(DateTime.Now) = "00:00" Then CallSub(Null, SendEmail)
End Sub

Good luck...

Hi @Peter Simpson, I think you are right with timer in service, so, I adapt your service code like this:
Just wondering if global variables of the services remains instancied with their values at the Service_create .

Thanks a lot.

Patrick

B4X:
#Region Module Attributes
#StartAtBoot: True
#StartCommandReturnValue: android.app.Service.START_STICKY
#End Region
'Service module
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Counter = 0 As Int
    Dim nAct As Notification
    Dim smsTimer As Timer
    Dim currentDayOfYear,currentYear,currentdayOfAllYears As Int
    Dim SMTP As SMTP
    Dim Datedujour As String
    Dim PE As PhoneEvents
    Dim ps As PhoneSms
    Dim PhoneId As PhoneId

End Sub
Sub Service_Create
      SMTP.Initialize(Main.SMTP_Server, Main.SMPT_Port, Main.SMTP_Username, Main.SMTP_Password, "SMTP")
    SMTP.StartTLSMode = True

    nAct.Initialize
   
    nAct.icon="icon2"
    nAct.Sound = False
    nAct.Vibrate = False
    nAct.Light = False
    nAct.OnGoingEvent = True
    nAct.SetInfo(Main.Progname &" Started", Counter & " Opérations", Main)
    nAct.Notify(1)
    'smsTimer.Initialize("sendsms", 1000)
    'smsTimer.Enabled = True

    currentYear= DateTime.GetYear(DateTime.Now)
    currentDayOfYear= DateTime.GetDayOfYear(DateTime.Now)
    ' on pourrait multiplier par 365, easier par 1000
    currentdayOfAllYears= currentDayOfYear*1000 + currentYear
   
    DateTime.dateformat="dd/MM/yyyy"
    Datedujour = DateTime.Date(DateTime.now)
    DateTime.dateformat = "yyyy-MM-dd"

     PE.Initialize("PhEvents")
    PE.InitializeWithPhoneState("PhEvents",PhoneId)
End Sub

Sub Service_Start(StartingIntent As Intent)
    StartServiceAt(Null, TimeToNextMinute, True) 'Service will restart every minute
    CallSub(Null, IsItMidnight)
End Sub

Sub TimeToNextMinute As Long
    Dim NextMin As Long
        NextMin = DateTime.Now + DateTime.TicksPerMinute
        NextMin = NextMin - (NextMin Mod DateTime.TicksPerMinute)
    Return NextMin
End Sub

Sub Service_Destroy
    nAct.Cancel(1)
End Sub

Sub IsItMidnight
    Dim dayndf As FactDay
    Dim cBody  As String
    DateTime.TimeFormat = "HH:mm"
    Log ("now " &   DateTime.Time(DateTime.Now))
    If DateTime.Time(DateTime.Now) = "00:00" Then
        dayndf.Initialize
        dayndf= tools.getexpense(currentDayOfYear,currentYear,-1)
        If dayndf.total > 0 Then
            'send mail
            cBody=createbody(dayndf)
            If Main.cSmsNo.Trim.Length >0 Then
                sendsms(Main.cSmsNo.Trim,cBody)
            End If
            If Main.cEmailTxt.Trim.Length >0 Then
                sendmail(Main.cEmailTxt.Trim,cBody,dayndf.Datedujour)
            End If
        End If
        nAct.SetInfo(Main.ProgName & " : " & Main.ProgVersion , "Opérations envoyés par eMail & SMS", "main")
        nAct.Notify(1)
        currentYear = DateTime.GetYear(DateTime.Now)
        currentDayOfYear = DateTime.GetDayOfYear(DateTime.Now)
        currentdayOfAllYears= currentDayOfYear *1000 + currentYear

        DateTime.dateformat="dd/MM/yyyy"
        Datedujour = DateTime.Date(DateTime.now)
        DateTime.dateformat = "yyyy-MM-dd"
        Counter=0
        CallSub(Main,"affiche_day")
   
    End If
End Sub
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
@imbault Global Variables in the service are reset once the service has be restarted. When I really need to do so, I store my variables in a Code Module.

In your case my original posted code will work just fine for you, you just need to do the following.
B4X:
'Try the following code
[CODE]
#Region Service Attributes
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

'SERVICE START
Sub Service_Start(StartingIntent As Intent)
    StartServiceAt(Null, TimeToNextMinute, True) 'Service will restart every minute
    CallSub(Null, IsItMidnight)
End Sub

'TIME TO NEXT WHOLE MINUTE
Sub TimeToNextMinute As Long
    Dim NextMin As Long
        NextMin = DateTime.Now + DateTime.TicksPerMinute
        NextMin = NextMin - (NextMin Mod DateTime.TicksPerMinute)
    Return NextMin
End Sub

'CHECK THE TIME TO SEE IF IT'S MIDNIGHT
Sub IsItMidnight
    DateTime.TimeFormat = "HH:mm"
    If DateTime.Time(DateTime.Now) = "00:00" Then CallSub(Null, SendEmail)
End Sub

'SEND EMAIL
Sub SendEmail
        dayndf.Initialize
        dayndf = tools.getexpense(currentDayOfYear, currentYear, - 1)
        If dayndf.total > 0 Then
            'Send mail
            cBody = createbody(dayndf)

            If Main.cSmsNo.Trim.Length > 0 Then sendsms(Main.cSmsNo.Trim, cBody)
            If Main.cEmailTxt.Trim.Length > 0 Then sendmail(Main.cEmailTxt.Trim, cBody, dayndf.Datedujour)
        End If

        nAct.SetInfo(Main.ProgName & " : " & Main.ProgVersion, "Opérations envoyés par eMail & SMS", "main")
        nAct.Notify(1)
        currentYear = DateTime.GetYear(DateTime.Now)
        currentDayOfYear = DateTime.GetDayOfYear(DateTime.Now)
        currentdayOfAllYears = currentDayOfYear * 1000 + currentYear

        DateTime.dateformat = "dd/MM/yyyy"
        Datedujour = DateTime.Date(DateTime.now)
        DateTime.dateformat = "yyyy-MM-dd"
        Counter = 0
        CallSub(Main, "affiche_day")
End Sub

And the rest is up to you ;)
Repost if it works or not, but I believe that it will. I've found customers of mine on the Play Store using Samsung S2's and S3's with my service app, and they have left 5 stars, so my service app is running just fine :)
 
Last edited:
Upvote 0
Top