New Google Play services stuff like low power location

Discussion in 'Android Questions' started by bluedude, May 28, 2013.

  1. warwound

    warwound Expert Licensed User

    Here's a basic example of detecting the device location using LocationClient, LocationRequest and LocationListener.
    An Activity:

    Code:
    Sub Process_Globals
       
    Dim LastLocation As Location
       
    Dim TrackingEnabled As Boolean=False
    End Sub

    Sub Globals
       
    Dim AltitudeLabel As Label
       
    Dim BearingLabel As Label
       
    Dim EnableToggle As ToggleButton
       
    Dim LatLngLabel As Label
       
    Dim SpeedLabel As Label
       
    Dim TimeLabel As Label
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("Main")

       EnableToggle.Checked=TrackingEnabled

       
    If LastLocation.IsInitialized Then
          LocationChanged
       
    End If
       
    End Sub

    Sub Activity_Resume

    End Sub

    Sub Activity_Pause (UserClosed As Boolean)

    End Sub

    Sub EnableToggle_CheckedChange(Checked As Boolean)
       TrackingEnabled=Checked
       
    If TrackingEnabled Then
          
    StartService(LocationTracker)
       
    Else
          
    StopService(LocationTracker)
       
    End If
    End Sub

    Sub LocationChanged
       AltitudeLabel.Text=LastLocation.Altitude
       BearingLabel.Text=LastLocation.Bearing
       LatLngLabel.Text=LastLocation.Latitude&
    ", "&LastLocation.Longitude
       SpeedLabel.Text=LastLocation.Speed
       TimeLabel.Text=
    DateTime.Time(LastLocation.Time)
    End Sub
    And a Service:

    Code:
    Sub Process_Globals

       
    Dim GooglePlayServicesHelper1 As GooglePlayServicesHelper
       
    Dim LocationClient1 As LocationClient
       
    Dim LocationListener1 As LocationListener
       
    Dim LocationRequest1 As LocationRequest

    End Sub

    Sub Service_Create
       LocationClient1.Initialize(
    "LocationClient1")

    End Sub

    Sub Service_Start (StartingIntent As Intent)

       
    If LocationClient1.IsConnected Then
          
    Log("LocationClient IsConnected")
       
    Else
          
    Dim ServiceStatus As Int=GooglePlayServicesHelper1.IsGooglePlayServicesAvailable
          
    Select ServiceStatus
             
    Case GooglePlayServicesHelper1.SUCCESS
                
    Log("GooglePlayServicesHelper IsGooglePlayServicesAvailable service available")
                
    Log("LocationClient Connecting")
                LocationClient1.Connect
             
    Case Else
                
    Log("GooglePlayServicesHelper IsGooglePlayServicesAvailable returned: "&ServiceStatus)
                
    Log("Google Play Services unavailable")
                
    StopService("")
          
    End Select
       
    End If
       
    End Sub

    Sub Service_Destroy

       
    If LocationRequest1.IsInitialized Then
          LocationClient1.RemoveLocationUpdates(LocationListener1)
       
    End If
       
       
    If LocationClient1.IsConnected Then
          LocationClient1.Disconnect
       
    End If
       
    End Sub

    Sub LocationClient1_Connected
       
    Log("LocationClient1_Connected")
       
       
    '   the GPS library is required as we are using the Location object
       '   check to see if a previous last location exists
       '   if it does then pass it to our Sub that handles the LocationListener LocationChanged event
       '   (force a location changed event before the LocationClient gets it's next GPS fix) 
       Dim LastLocation As Location=LocationClient1.GetLastLocation
       
    If LastLocation.IsInitialized Then
          
    Log("LastLocation being passed to LocationListener1_LocationChanged")
          LocationListener1_LocationChanged(LastLocation)
       
    End If

       LocationRequest1.Initialize
       
       
    '   detailed info on the LocationRequest parameters can be found:
       '   http://developer.android.com/training/location/receive-location-updates.html
       '   http://developer.android.com/reference/com/google/android/gms/location/LocationRequest.html
       
       LocationRequest1.SetFastestInterval(
    1000*1)         '   think of this as the fastest updates that your event handling Sub can handle
       LocationRequest1.SetInterval(1000*6)            '   this is the desired frequency of location update (units of milliseconds)
       LocationRequest1.SetNumUpdates(9999)            '   the maximum number of updates that should be reported, after this number no more will be reported
       LocationRequest1.SetPriority(LocationRequest1.PRIORITY_HIGH_ACCURACY)   '   the desired accuracy/power usage mode
       
       LocationListener1.Initialize(
    "LocationListener1")
       
       LocationClient1.RequestLocationUpdates(LocationRequest1, LocationListener1)
       
       
    End Sub

    Sub LocationClient1_ConnectionFailed(ErrorCode As Int)
       
    Log("LocationClient1_ConnectionFailed ErrorCode="&ErrorCode)
       
    StopService("")
    End Sub

    Sub LocationClient1_Disconnected
       
    Log("LocationClient1_Disconnected")
       
    StopService("")
    End Sub

    Sub LocationListener1_LocationChanged (Location1 As Location)
       Main.LastLocation=Location1
       
    CallSub(Main, "LocationChanged")
    End Sub
    So in the Activity the user can use the ToggleButton to start and stop the Service.
    The Service, when running, listens for location updates.
    The Activity has a Process Global Location object that is initially not initialized.
    When the Service gets a location update it sets the location update as the Activity Process Global Location object and calls a Sub in the Activity to update the Activity layout.
    If the service is running and the user exits the app then the service will continue to run and update the Process Global, if the Activity is resumed it will update it's layout with the values of the last reported location.
    All pretty straightforward stuff!

    Lines 70 to 73 of the Service define the accuracy and frequency of the location requests and therefore the amount of device battery power that will be used.
    It's listening for maximum accuracy location changes every 6000 milliseconds.
    After 9999 location updates have bene reported presumably the LocationClient will report no more.

    Compile the code and look in the manifest.xml file, you'll see:

    Code:
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    This permission is currently hardcoded into the library.
    You can use the Location API with either android.permission.ACCESS_FINE_LOCATION or android.permission.ACCESS_COARSE_LOCATION.
    If that permission in the manifest was ACCESS_COARSE_LOCATION instead of ACCESS_FINE_LOCATION then:

    Sometimes it will be desirable/preferable to use android.permission.ACCESS_COARSE_LOCATION instead of android.permission.ACCESS_FINE_LOCATION.

    Question: Shall i therefore remove the hardcoded android.permission.ACCESS_FINE_LOCATION from the library and leave the b4a developer to manually add the permission they require to the manifest file?
    Or i believe i could leave the android.permission.ACCESS_FINE_LOCATION hardcoded and if a b4a developer wants to instead use android.permission.ACCESS_COARSE_LOCATION there are manifest editor commands that can be used to remove the unwanted permission and add the wanted permission.

    Neither solution is perfect - the b4a developer will be required to manually manage their manifest permissions.

    LocationClient, LocationRequest and LocationListener work well and can be considered to be ready for use in your b4a apps.

    Be sure to check out both links to the android documentation in the code to read about the various LocationRequest parameters.
    The FastestUpdate parameter is particularly interesting - if another app on the device is getting location updates then these location updates can also be passed to your app. The FastestInterval parameter tells android how fast your code can handle location updates so that it doesn't report updates (raise events) faster than your code can handle.

    Demo project attached.

    Martin.

    (PS Please do comment on the permissions and how you think it is best to handle them).
     

    Attached Files:

  2. Harris

    Harris Well-Known Member Licensed User

    It is too bad that coarse or fine cant be set within the app.
    If the device is constantly powered (as mounted in a powered vehicle cradle), then fine is great. Otherwise, coarse is needed to save battery. You never know how the app will be used - in my case....

    Thanks for your wonderful work.
     
  3. marcel

    marcel Active Member Licensed User

    Code:
    B4A line: 77
    LocationClient1.RequestLocationUpdates(LocationRequest1, LocationListener1)
    javac 
    1.6.0_26
    src\uk\co\martinpearman\b4a\locationapidemo\locationtracker.java:
    118: package com.google.android.gms.location does not exist
    _locationclient1.RequestLocationUpdates((com.google.android.gms.location.LocationRequest)(_locationrequest1.getObject()),(com.google.android.gms.location.LocationListener)(_locationlistener1.getObject()));
                                                                            ^
    1 error
    I think I am missing some files?
     
  4. warwound

    warwound Expert Licensed User

    Probably missing the latest version of google-play-services.jar.
    See my post here: http://www.basic4ppc.com/forum/basi...stuff-like-low-power-location.html#post172587

    Martin.
     
  5. marcel

    marcel Active Member Licensed User

    I had an older version. I updated everthing and now it works!

    :sign0060:
     
  6. marcel

    marcel Active Member Licensed User

    Hi Martin,

    I did leave tonight the test program running until this morning the battery was complete empty. I expected that it will only use the Cell Tower or last Know position becuase it was not moved at all.

    When I read at the documentation, I am not sure I get it. Or I did read the wrong one :)

    When does it use Cell Tower position and when does it switch to GPS? Is this something you need to do yourself or is this automaticly?

    And what is the difference between the LocationManager and this?

    Can you help me a little bit to keep on track. Currently I am using only the GPS module in the app but I got lot of complains because of the battery drain.
     
  7. basil99

    basil99 Active Member Licensed User

    Hi, warwound

    thanks for this lib, here some test results:

    DEVICE: No SIM Card, GPS build in
    OS: 2.2
    NETWORK: WiFi connection
    BLUETOOTH: Connected to the PC


    works fine and fast.

    Howerer, I compare the results with Erel's GPS sample http://www.basic4ppc.com/forum/basic4android-getting-started-tutorials/6592-gps-tutorial.html#post38535. Your lib is much faster, i get location almost immediatly. GPS sample sometimes requires several minutes to display Lat/Lng. But i'm confused with some difference in results ( using Location.ConvertToSeconds ):

    Erel GPS sample:
    Lat: MM:SS:1.57
    Lng: MM:SS:20.83

    values are stable

    Yor lib:
    Lat: MM:SS:2.41 - 2.42
    Lng: MM:SS:20.84 - 20.99

    values are changing permanently, never mind phone is not moved at all, just on it place on the table

    my question is - what results are more accurate from your point of view ?
     
    Last edited: Jun 24, 2013
  8. jmon

    jmon Well-Known Member Licensed User

    Device: HTC Desire
    OS: Android 2.2, Rooted
    WIFI: OFF


    -->> I don't get anything working. The application launches, but no location, speed, altitude ... is found. Even "Time" isn't displayed, so it means the event LocationChanged isn't triggered.

    WIFI: ON
    -->> Ok, "lat,lng" works with wifi ON, but no altitude, speed or bearing


    So what is it? the app cannot retrieve my location from the towers?

    Also, regarding the permissions, I vote for the way it is now, in version 0.05, with both permissions forced, because the reality of this library is that it retrieves a very accurate location.
     
    Last edited: Jun 24, 2013
  9. netchicken

    netchicken Active Member Licensed User

    Working with Location i find that with GPS off you get the GPS lat Lon, but thats all.

    With GPS on you get the other location properties, speed, altitude etc.

    Also the update time is much faster with GPS on.
     
    Last edited: Jun 24, 2013
  10. jmon

    jmon Well-Known Member Licensed User

    After doing more tests, I found that the tower reception is very random. It only works in 80% of my tests. I feel that it doesn't work properly in interior.
     
  11. marcel

    marcel Active Member Licensed User

    Hi,

    I drove arround with the test program but after a while it stoped working. I thought it might be the `SetNumUpdates` so I restarted the program but still had some trouble. I restarted the phone and it worked again.

    But also sometime without restarting I see the time of the update changed again.

    I have an Samsung Android S2 4.1.2
     
  12. corwin42

    corwin42 Expert Licensed User

    @warwound
    Are you still working on this library or is the version you posted a month ago the final version?
    Will you open a new thread for it in the Libraries forum?
     
  13. warwound

    warwound Expert Licensed User

    I think thats a good idea - this thread has gone a bit stale, i've been too busy to keep track of the questions and help with replies.

    I'll get a new thread started a bit later today.

    Martin.
     
  14. corwin42

    corwin42 Expert Licensed User

    I haven't seen a new thread in libraries forum until now. Anyway I will start to use this library now in my projects.

    Thanks very much warwound.
    Good work!
     
    ValDog likes this.
  15. ValDog

    ValDog Active Member Licensed User

    Martin,

    As always - great work!
     
  16. marcel

    marcel Active Member Licensed User

    Hi,

    I would like to user the library. In my test program it works fine. But when I convert it to my app I get an error:

    Code:
    GooglePlayServicesHelper IsGooglePlayServicesAvailable service available
    LocationClient Connecting
    LocationClient1_Connected
     
     
    java.lang.IllegalStateException: 
    Not connected. Call connect() and wait for onConnected() to be called.
     
     
        at com.google.android.gms.internal.p.n(Unknown Source)
        at com.google.android.gms.internal.ce.a(Unknown Source)
        at com.google.android.gms.internal.ce$c.n(Unknown Source)
        at com.google.android.gms.internal.cd.getLastLocation(Unknown Source)
        at com.google.android.gms.internal.ce.getLastLocation(Unknown Source)
        at com.google.android.gms.location.LocationClient.getLastLocation(Unknown Source)
        at uk.co.martinpearman.b4a.android.gms.location.LocationClient.GetLastLocation(LocationClient.java:
    107)
        at com.yazula.android.update._locationclient1_connected(update.java:
    149)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    511)
        at anywheresoftware.b4a.BA.raiseEvent2(BA.java:
    173)
        at anywheresoftware.b4a.BA.raiseEvent(BA.java:
    157)
        at uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient$
    1.onConnected(LocationClient.java:23)
        at com.google.android.gms.internal.p.k(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$b.p(Unknown Source)
        at com.google.android.gms.internal.p$a.handleMessage(Unknown Source)
        at android.os.Handler.dispatchMessage(Handler.java:
    99)
        at android.os.Looper.loop(Looper.java:
    137)
        at android.app.ActivityThread.main(ActivityThread.java:
    4921)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    1027)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    794)
        at dalvik.system.NativeStart.main(Native Method)
    java.lang.RuntimeException: java.lang.IllegalStateException: 
    Not connected. Call connect() and wait for onConnected() to be called.
     
     
        at anywheresoftware.b4a.BA.raiseEvent2(BA.java:
    199)
        at anywheresoftware.b4a.BA.raiseEvent(BA.java:
    157)
        at uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient$
    1.onConnected(LocationClient.java:23)
        at com.google.android.gms.internal.p.k(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$f.a(Unknown Source)
        at com.google.android.gms.internal.p$b.p(Unknown Source)
        at com.google.android.gms.internal.p$a.handleMessage(Unknown Source)
        at android.os.Handler.dispatchMessage(Handler.java:
    99)
        at android.os.Looper.loop(Looper.java:
    137)
        at android.app.ActivityThread.main(ActivityThread.java:
    4921)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
    1027)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:
    794)
        at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.lang.IllegalStateException: 
    Not connected. Call connect() and wait for onConnected() to be called.
        at com.google.android.gms.internal.p.n(Unknown Source)
        at com.google.android.gms.internal.ce.a(Unknown Source)
        at com.google.android.gms.internal.ce$c.n(Unknown Source)
        at com.google.android.gms.internal.cd.getLastLocation(Unknown Source)
        at com.google.android.gms.internal.ce.getLastLocation(Unknown Source)
        at com.google.android.gms.location.LocationClient.getLastLocation(Unknown Source)
        at uk.co.martinpearman.b4a.android.gms.location.LocationClient.GetLastLocation(LocationClient.java:
    107)
        at com.yazula.android.update._locationclient1_connected(update.java:
    149)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:
    511)
        at anywheresoftware.b4a.BA.raiseEvent2(BA.java:
    173)
        ... 
    15 more
    Could this because of timing issues?
     
  17. warwound

    warwound Expert Licensed User

    Is it connecting but then disconnecting?

    Can you add a sub to listen for the LocationClient Disconnected event and see if that event is raised after the Connected event?
    You might also want to add a sub to listen for the LocationManager ConnectionFailed(ErrorCode As Int) event and see if that event is raised.

    Martin.
     
  18. marcel

    marcel Active Member Licensed User

    Thanks Martin!! I found it using your suggestions! I used
    Code:
    Dim LastLocation As Location=LocationClient1.GetLastLocation
    before it was even open.

    Great library!!
     
  19. marcel

    marcel Active Member Licensed User

    From Google

    Could you also implement the ErrorDialog?
     
  20. corwin42

    corwin42 Expert Licensed User

    Since B4A 3.20 you can add it yourself with the #AdditionalRes attribute and JavaObject/Reflection library.

    - Download the Play Services SDK with the Android SDK Manager.
    - Copy the ?\android-sdk\extras\google\google_play_services\libproject\google-play-services_lib\res to some folder
    - In your B4A Project add this folder with the #AdditionalRes attribute.

    Code:
    #AdditionalRes: <path_to_the_folder>, com.google.android.gms
    In Activity_Resume write the following:

    Code:
    Sub Activity_Resume
        
    Dim gpsHelper As GooglePlayServicesHelper
        
    Dim errorCode As Int
       
        errorCode = gpsHelper.IsGooglePlayServicesAvailable
        
    If errorCode <> gpsHelper.SUCCESS Then
            
    Log("Play Services not available -> try to install")
       
            
    Dim jo As JavaObject
            
    Dim r As Reflector
           
            jo.InitializeStatic(
    "com.google.android.gms.common.GooglePlayServicesUtil")
            
    If jo.RunMethod("isUserRecoverableError"Array As Object(errorCode)) Then
                jo.RunMethodJO(
    "getErrorDialog"Array As Object(errorCode, r.GetActivity, 9999)).RunMethod("show"Null)
            
    Else
                
    Log("Play Services not available for this device")
                
    'Show error message here
            End If
        
    Else
            
    Log("Play Services available")
        
    End If
    End Sub
     
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