Android Tutorial Service Modules

ericvanderhoeven

Member
Licensed User
Longtime User
Creating ONLY a service

Hi,

is it possible to just create a service without a (main) activity?

I wish to make a battery counter service = it updates a counter in a TXT file every time the battery gets charged. This allows me to see how often a battery has been charged during its life and more accurately determine when it is time to replace it.

The service should start automatically at boot.

I am trying and most of it works but I can not seem to get rid off the initial activity and users need to manually close it. For this I now use a simple layout of a screen with a button that once pressed, kills the activity.

This all works relatively OK but it is a bit messy. And the service seems to stop after a certain period of time... No a clue as to why..

Any suggestions?

Thanks,

Eric
 

ericvanderhoeven

Member
Licensed User
Longtime User
How to initiate a service Notification?


Hi Erel,

I am trying to use service.startforeground() in order for my service not to get killed by the OS but I have to give it an ID -I've tried 0- and a Notification. How do you set up such a notification? Seems to be an array?

More bluntly, I am merely looking for a way for my service to run permanently.. I do not necessarily require this notification to be passed on to the OS but this service.startforeground() seems to be the only one that prevents a service from being killed and requires it?

Thanks,

Eric
 

melamoud

Active Member
Licensed User
Longtime User

I would not recommand to use startForeground, do you really need the service to run all the time ? or every few seconds or minuets is good enough ? (more friendly toward other apps) - so you an use startServiceAt (now + X miliseconds) when you are at the end of your service_start sub.

or (better in my mind) find the right event you can listen to , and make sure your service is register (manifest) to wake up on that event (better assuming you can find that event) because the service will wake up on that event no matter if the activity was running or not (after boot for example)

example could be (I have not tried it, but it seems like the right event)
at Monitoring the Battery Level and Charging State | Android Developers
 

melamoud

Active Member
Licensed User
Longtime User
it seems (from reading only) that all you need to do it register to that event and in your start sub, update the data / app / activity you want to update (when the % change)
 

ericvanderhoeven

Member
Licensed User
Longtime User
register service to wake up


Hi Melamoud,

thank you for your response. I am very interested to wake up (or (re)start) my service the moment such event happens. This event is already correctly triggered by Android the moment a DC charger is plugged in. At that exact moment it raises device_batterychanged(with plugged = true). Only at that time do I wish to have the service running in order to simply add 1 to a battery counter of how many times the battery has been charged.

How to do this? I am a novice in editing the manifest..

Thanks,

Eric
 

melamoud

Active Member
Licensed User
Longtime User
go to project menu, choose manifest editor
add the following line
B4X:
AddReceiverText(s1, <intent-filter>
    <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>)

replace the s2 with your service module name, and the PHONE_STATE with the event you want to listen to (
you can add as many lines like that as you want to call other services or same service with other events

if you need persmissions (special permissions) you will need to add lines like this:
B4X:
AddPermission("android.permission.READ_PHONE_STATE")

the service start sub will be called and the parameters will be in the intent (and the extra) parameters,

if you need more help let me know.
 

ericvanderhoeven

Member
Licensed User
Longtime User
external events


Hi melamoud,

I need a little push... Here is my service module code so far =

B4X:
Sub Process_Globals
   Dim battery_counter As Int
   Dim device As PhoneEvents
   Dim root, settingspath As String
   Dim Charging_Now, Charging_Before As Boolean   
End Sub

Sub Service_Create
   device.Initialize("device")
   root=File.DirRootExternal
   settingspath = root & "/mpTouch/settings/"
   If File.Exists(settingspath, "battery.txt") Then
      battery_counter = File.ReadString(settingspath, "battery.txt")
   Else 
      File.WriteString(settingspath, "battery.txt", battery_counter)
   End If
End Sub

Sub Service_Start (StartingIntent As Intent)
End Sub

Sub Service_Destroy
End Sub

Sub device_BatteryChanged(Level As Int, Scale As Int, Plugged As Boolean, Intent As Intent)
   If Plugged Then 
      Charging_Now = True
   Else 
      Charging_Now = False
   End If
   If (Charging_Before = False) AND Charging_Now Then
      battery_counter = battery_counter+1
      File.WriteString(settingspath, "battery.txt", battery_counter)
   End If
   Charging_Before = Charging_Now
   ToastMessageShow("counter: " &battery_counter, False)  
End Sub

Works perfect. But the service just vanishes after some time. Don't know why but my guess is that it is kicked out by Android. The reason I went exploring StartForeground() as that seems to prevent Android from killing it.

I am still a bit puzzled by your suggestions. Especially how to ''jump'' into my code via these ''external'' events taking place. I normally write code that listens to it and it then jumps to the sub dealing with that event (and indeed waste a lot of resources while doing this)

So if you can give me just a few more tips on the basis of my current code, I would appreciate that very much.

Thanks,

Eric
 

melamoud

Active Member
Licensed User
Longtime User
if you use the events method your Service_Start will get called every time the battery change (guessing according to the documentation) - you should check that
just add a log of StartingIntent and the StartingIntent.extraToString at the begining of your Service_start and wait to see how android cal it when the % change

my guess is that you will be able to extract (from the extra) all / most of the needed details to call your BatteryChanged sub.

first try to edit the manifest , add the logs, and wait for the battery change to happen (also plug / unplug the device) according to the docs, you will get few parameters in the extra: (when listening to ACTION_BATTERY_CHANGED)
you have one param EXTRA_STATUS that the value will be FULL or in charging
you have one param EXTRA_PLUGGED the value will be USB or AC


if you listen to events ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED
seems to be the same, so if the first one does not work, try these two..

you will also get int the extra two more params EXTRA_LEVEL and EXTRA_SCALE

so it seems you will get everything you need

send me snippet of the logs
 

melamoud

Active Member
Licensed User
Longtime User
I played with it a bit, and sorry I was wrong,
apperntly the specific event (battery change) which is the one you need to know the level and scale can only be registered dynamicly using (in B4A) BroadCastReceiver lib.

you can not (in android) register for this event using the manifest - sorry (not sure why they did it)

so I think the way to do this is using startServiceAt("",DateTime.Now+60*DateTime.TicksPerSecond,True)
at the end of your Service_Start sub,
this will make sure that your start will be called every 60 seconds , and they you can try to see the batter level see if it changed etc
sorry!
 

ericvanderhoeven

Member
Licensed User
Longtime User
starting service on event android.intent.action.BATTERY_CHANGED


I added to my manifest =

B4X:
AddReceiverText(autostart, <intent-filter>
    <action android:name="android.intent.action.BATTERY_CHANGED" />
    </intent-filter>)
AddPermission("android.permission.BATTERY_CHANGED")

I also added a log in my service_start to see if it actually gets there =

B4X:
Sub Service_Start (StartingIntent As Intent)
   Log("Service start called")
   ToastMessageShow("called", False)  
End Sub

Doesn't work at all....

Internet =

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/Ew4wqAJ_ois

Hmmmm...

Eric
 

melamoud

Active Member
Licensed User
Longtime User
asI wrote on the later post, Iplayed with it and it is not working, you have to use startServiceAt approach
 

ericvanderhoeven

Member
Licensed User
Longtime User
running a service permanently

asI wrote on the later post, Iplayed with it and it is not working, you have to use startServiceAt approach

Hi melamoud,

my reply crossed yours (or I was just not paying attention...). Thank you for all your help, I am now testing the app. I think I have solved all of it with the help of you and snippets on this forum. Here is my result for those following this thread or are searching for similar things.

Setup =

A/ In Activity_Create, call the service via StartService(service module name)
B/ Follow up by Activity.Finish (so the activity is no longer relevant)
C/ Create a Notification so you can make use of
D/ Service.StartForeground(ID,Notification). This keeps the service running and also does some rather cool stuff in the task bar.
E/ set the service to run at startup (when in the tab of the service, go to Project, Service Properties)

B4X:
Sub Process_Globals
      Dim sNotif As Notification
      Dim device As PhoneEvents
End Sub

Sub Service_Create
   sNotif.Initialize
   sNotif.Icon = "icon"
   sNotif.SetInfo("Battery Counter by imagineear","Monitoring...",Main)
   sNotif.Sound = False
   sNotif.Notify(1)   
   Service.StartForeground(1,sNotif)
end sub

Sub device_BatteryChanged(Level As Int, Scale As Int, Plugged As Boolean, Intent As Intent)
   If Plugged Then 
      Charging_Now = True
   Else 
      Charging_Now = False
   End If
   If (Charging_Before = False) AND Charging_Now Then
      battery_counter = battery_counter+1
      File.WriteString(settingspath, "battery.txt", battery_counter)
   End If
   Charging_Before = Charging_Now
End Sub

I have left out some non-relevant declarations etc. If anyone can not get this to work at all, drop me a line.

Thanks,

Eric
 

jeeradate

Member
Licensed User
Longtime User
How to show Service Status

I modified the example in this thread to show Service Status but I don't work. I had tested all the alternative but didn't work.
I have to double click the Start and Stop Button to have the correct status shown.

:sign0163:

Activity Module Code


B4X:
'Activity module
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Timer1 As Timer
    Timer1.Initialize("Timer1",1000)
    
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim StartS As Button
    Dim StopS As Button
    Dim Label1 As Label
    Dim Label2 As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout1")
End Sub
Sub Activity_Resume
    UpdateStatus
    Label1.Text= ServiceM.Counter
    If IsPaused(ServiceM)= False Then
        Timer1.Enabled=True
    End If 
End Sub
Sub Activity_Pause (UserClosed As Boolean)
    Timer1.Enabled=False
End Sub
Sub Timer1_Tick
    Label1.Text= ServiceM.Counter
End Sub
Sub StopS_Click
    CancelScheduledService(ServiceM)  ' to end the command StartServiceAt
    StopService(ServiceM)
    UpdateStatus
    Timer1.Enabled=False
End Sub
Sub StartS_Click
    Timer1.Enabled=True
    StartService(ServiceM)
    UpdateStatus
End Sub
Sub UpdateStatus
    If IsPaused(ServiceM)=True Then
        Label2.Text = "Service is Paused"
    Else
        Label2.Text = "Service is Active"
    End If 
End Sub
Service Module code

B4X:
'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 TimerService As Timer
    Dim Counter As Int
    Counter = 0
    Dim N As Notification
End Sub
Sub Service_Create
    'TimerService.Initialize("TimerService",1000)
    'TimerService.Enabled=True
    
    n.Initialize
    n.Icon = "icon"
    n.Sound = False
    n.Vibrate = False
    n.Light = False
    n.OnGoingEvent=True
    
    n.SetInfo("Timer Start", Counter, Main) 
    'Change Main (above) to "" if this code is in the main module.
    n.Notify(1) 
    
End Sub

Sub Service_Start (StartingIntent As Intent)
    Counter = Counter+1
    n.SetInfo("Timer Start", Counter, Main) 
    'Change Main (above) to "" if this code is in the main module.
    n.Notify(1) 
    
    StartServiceAt("",DateTime.Now+DateTime.TicksPerSecond,True)
End Sub

Sub Service_Destroy
    n.Cancel(1)
End Sub
 

Attachments

  • serviceM.zip
    9.5 KB · Views: 816
Last edited:

melamoud

Active Member
Licensed User
Longtime User
might be timing isues, it takes time for the service to start / stop, you need to wait for ut, currenly you update the status immidiatly after the call to start or stop.

I suggest you implement a timer (or use the one you already have) to check for status every X seconds and update label 2 (or just wait (maybe using a timer) , after you start or cancel , a bit and update label2
 

jeeradate

Member
Licensed User
Longtime User


Thank you very much, I added some delay using the only timer I had.
And it work !,
Thank You very much.



B4X:
'Activity module
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Timer1 As Timer
    Timer1.Initialize("Timer1",1000)

    
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim StartS As Button
    Dim StopS As Button
    Dim Label1 As Label
    Dim Label2 As Label
    Dim Status As Boolean
    Dim TimerOff As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout1")
    If FirstTime Then 
        Status = False
        TimerOff = False
    End If
End Sub
Sub Activity_Resume
    UpdateStatus
    Label1.Text= ServiceM.Counter
    If IsPaused(ServiceM)= False Then
        Timer1.Enabled=True
    End If 
End Sub
Sub Activity_Pause (UserClosed As Boolean)
    Timer1.Enabled=False
End Sub
Sub Timer1_Tick
    Label1.Text= ServiceM.Counter
    If Status = True Then
        UpdateStatus
        Status = False
    End If     
    If TimerOff = True Then
        TimerOff = False
        Timer1.Enabled=False
    End If
End Sub
Sub StopS_Click
    CancelScheduledService(ServiceM)  ' to end the command StartServiceAt
    StopService(ServiceM)
    Status = True
    TimerOff = True
    
End Sub
Sub StartS_Click
    Timer1.Enabled=True
    StartService(ServiceM)
    Status = True
End Sub
Sub UpdateStatus
    If IsPaused(ServiceM)=True Then
        Label2.Text = "Service is Paused"
    Else
        Label2.Text = "Service is Active"
    End If 
End Sub
 
Last edited:

BaGRoS

Active Member
Licensed User
Longtime User
Service runing if I use Compile & Run from b4a, and not runing if I install from sd card?!

Service module
B4X:
#Region  Service Attributes 
   #StartAtBoot: True
#End Region

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

Dim si As SmsInterceptor
Dim SMSs As PhoneSms

End Sub
Sub Service_Create

      'incoming messages
      si.Initialize2("si",2147483647)
      'ToastMessageShow("Uruchomione...", True)
      
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Sub Service_Destroy

   si.StopListening
   
End Sub

Sub si_MessageReceived(From As String, Body As String) As Boolean
    
   'Log(From)
   'ToastMessageShow(From & " - " & Body,False)
   
    If From.Contains("666666666") Then
   
    'Log ("Odebrało się")
         'teraz tworze wiadomosc
      Dim txt As String
      txt = "Wiadomosc odebrana od: "
      txt = txt & From & ";"
      txt = txt & DateTime.Date(DateTime.Now) & " " & DateTime.Time(DateTime.Now) & ";"
      txt = txt & Body
      SMSs.Send("+48888888888",txt)
      Log(txt)
      
    End If
    
End Sub
 

BaGRoS

Active Member
Licensed User
Longtime User
my manifest

B4X:
<?xml version="1.0" encoding="utf-8"?>
<manifest
   xmlns:android="http://schemas.android.com/apk/res/android"
   package="b4a.example"
   android:versionCode="1"
   android:versionName="4.2.1"
   android:installLocation="internalOnly">
   
   <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/>
   <supports-screens android:largeScreens="true" 
       android:normalScreens="true" 
       android:smallScreens="true" 
       android:anyDensity="true"/>
   <uses-permission android:name="android.permission.RECEIVE_SMS"/>
   <uses-permission android:name="android.permission.SEND_SMS"/>
   <uses-permission android:name="android.permission.READ_SMS"/>
   <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
   <application
      android:icon="@drawable/icon"
      android:label="Testowy Messaging Service">
      <activity
         android:windowSoftInputMode="stateHidden"
         android:launchMode="singleTop"
         android:name=".main"
         android:label="Testowy Messaging Service"
         android:screenOrientation="unspecified">
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <!--<category android:name="android.intent.category.LAUNCHER" /> -->
         </intent-filter>
         
      </activity>
      <service android:name=".sms">
      </service>
      <receiver android:name=".sms$sms_BR">
         <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED"/>
         </intent-filter>
      </receiver>
      <service android:name=".smsr">
      </service>
      <receiver android:name=".smsr$smsr_BR">
         <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED"/>
         </intent-filter>
      </receiver>
   </application>
</manifest>
 

BaGRoS

Active Member
Licensed User
Longtime User
1. install from IDE with <!--<category android:name="android.intent.category.LAUNCHER" /> --> - services work
2. install from sd card with <!--<category android:name="android.intent.category.LAUNCHER" /> --> - services not work
3. install from sd card without <!--<category android:name="android.intent.category.LAUNCHER" /> --> - services not work
4. install from sd card without <!--<category android:name="android.intent.category.LAUNCHER" /> --> AND launch ONE TIME - service WORK with every boot!!!!!!

IDE start the program after installation is probably why the services are running ??!
 
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…