Android Tutorial Service Modules

Discussion in 'Tutorials & Examples' started by Erel, Jan 27, 2011.

  1. ericvanderhoeven

    ericvanderhoeven Member Licensed 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
     
  2. ericvanderhoeven

    ericvanderhoeven Member Licensed 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
     
  3. melamoud

    melamoud Active Member Licensed 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
     
  4. melamoud

    melamoud Active Member Licensed 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)
     
  5. ericvanderhoeven

    ericvanderhoeven Member Licensed 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
     
  6. melamoud

    melamoud Active Member Licensed User

    go to project menu, choose manifest editor
    add the following line
    Code:
    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:
    Code:
    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.
     
  7. ericvanderhoeven

    ericvanderhoeven Member Licensed User

    external events

    Hi melamoud,

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

    Code:
    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 = FalseAND 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
     
  8. melamoud

    melamoud Active Member Licensed 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
     
  9. melamoud

    melamoud Active Member Licensed 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!
     
  10. ericvanderhoeven

    ericvanderhoeven Member Licensed User

    starting service on event android.intent.action.BATTERY_CHANGED

    I added to my manifest =

    Code:
    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 =

    Code:
    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
     
  11. melamoud

    melamoud Active Member Licensed User

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

    ericvanderhoeven Member Licensed User

    running a service permanently

    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)

    Code:
    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 = FalseAND 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
     
  13. jeeradate

    jeeradate Member Licensed 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


    Code:
    '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

    Code:
    '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
     

    Attached Files:

    Last edited: Dec 30, 2012
  14. melamoud

    melamoud Active Member Licensed 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
     
  15. jeeradate

    jeeradate Member Licensed User


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

    :)

    Code:
    '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: Dec 31, 2012
  16. BaGRoS

    BaGRoS Member Licensed User

    Service runing if I use Compile & Run from b4a, and not runing if I install from sd card?!

    Service module
    Code:
    #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 StringAs 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
     
  17. Erel

    Erel Administrator Staff Member Licensed User

    In order for an app to "start at boot" it must be installed internally. The IDE will automatically set the correct value in the manifest (unless you override it with the manifest editor).
     
  18. BaGRoS

    BaGRoS Member Licensed User

    my manifest

    Code:
    <?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>
     
  19. BaGRoS

    BaGRoS Member Licensed 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: May 18, 2013
  20. Erel

    Erel Administrator Staff Member Licensed User

    When you say "services not work" you mean that the services do not start after a boot?

    I also recommend you to remove the "android.intent.action.MAIN" action.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice