Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPS Passive recording feature #275

Merged
merged 85 commits into from
May 2, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
60462f3
Merge pull request #21 from onaio/master
eotin Jan 28, 2019
88c93c2
Merge pull request #22 from eotin/master
eotin Jan 28, 2019
1be6529
Merge pull request #23 from onaio/master
eotin Feb 27, 2019
3a6444b
Merge pull request #24 from eotin/master
eotin Feb 27, 2019
01ea0ce
Fix issue in the WMTS layout
eotin Feb 27, 2019
8a588ab
Fix spelling Wmts activity
eotin Mar 4, 2019
6749217
Add TrackingService functionality
eotin Mar 15, 2019
dcbcd1d
Add recording images
eotin Mar 19, 2019
909beb6
Add Unit Tests
eotin Mar 20, 2019
e441be4
Merge pull request #25 from onaio/master
eotin Mar 20, 2019
d789e38
Merge branch 'eo/merge_passive_record_location' into Develop
eotin Mar 20, 2019
2b06ba4
Merge pull request #26 from eotin/Develop
eotin Mar 20, 2019
e8b4a74
Fix import issue after merging from onaio/master
eotin Mar 20, 2019
8c0e4d5
Merge pull request #27 from eotin/eo/merge_passive_record_location
eotin Mar 20, 2019
3875380
Merge pull request #28 from eotin/master
eotin Mar 20, 2019
17c85d6
Fix code regarding Codacy/PR Quality Review
eotin Mar 20, 2019
bca4fd3
Merge pull request #29 from eotin/Develop
eotin Mar 20, 2019
6e098a0
Fix code regarding Codacy/PR Quality Review
eotin Mar 20, 2019
6bf33a3
Merge pull request #30 from eotin/Develop
eotin Mar 20, 2019
2ba6a28
Fix code regarding Codacy/PR Quality Review
eotin Mar 20, 2019
789c88e
Merge pull request #31 from eotin/Develop
eotin Mar 20, 2019
a42d1a0
Fix code regarding Codacy Bot
eotin Mar 21, 2019
c8aa557
Merge pull request #32 from eotin/Develop
eotin Mar 21, 2019
44198b3
Merge pull request #33 from onaio/master
eotin Mar 25, 2019
2174318
Merge pull request #34 from eotin/master
eotin Mar 25, 2019
0b20657
Uncomment developmentKujakuModulesImport to be able to build successf…
eotin Mar 25, 2019
6f1ad3d
Merge pull request #35 from eotin/Develop
eotin Mar 25, 2019
b73985b
Avoid catching generic exceptions such as NullPointerException, Runti…
eotin Mar 25, 2019
914c751
Merge pull request #36 from eotin/Develop
eotin Mar 25, 2019
8965585
Increase unit tests Coverage
eotin Mar 25, 2019
707d494
Merge pull request #37 from eotin/Develop
eotin Mar 25, 2019
ee76564
Fix unused import
eotin Mar 25, 2019
a4021bf
Merge pull request #38 from eotin/Develop
eotin Mar 25, 2019
f4aef1f
Fix crash on activity after updating the mapbox sdk
eotin Mar 25, 2019
19e9efd
Merge pull request #39 from eotin/Develop
eotin Mar 25, 2019
ac68d4d
Add TrackingStorage Tests
eotin Mar 26, 2019
eee880b
Merge pull request #40 from eotin/Develop
eotin Mar 26, 2019
48156ac
Avoid catching generic exceptions such as NullPointerException, Runti…
eotin Mar 26, 2019
27809c0
Merge pull request #41 from eotin/Develop
eotin Mar 26, 2019
02d6f72
Fix test errors after having changed the KujakuMapView.java file
eotin Mar 27, 2019
785bf20
Merge pull request #42 from eotin/Develop
eotin Mar 27, 2019
eaad1d8
Add Test for Class WmtsLayer
eotin Apr 3, 2019
404c5d5
Merge pull request #43 from eotin/Develop
eotin Apr 3, 2019
dd44d9a
Add Test for Class BaseStorage / TrackingStorage
eotin Apr 3, 2019
530f886
Merge pull request #44 from eotin/Develop
eotin Apr 3, 2019
e342a58
Add Tests coverage for TrackingService class
eotin Apr 3, 2019
17251ac
Merge pull request #45 from eotin/Develop
eotin Apr 3, 2019
26d1afe
Fix "Document empty method body" code review
eotin Apr 3, 2019
e628dcb
Merge pull request #46 from eotin/Develop
eotin Apr 3, 2019
c2fa462
Update TrackingServiceTest class
eotin Apr 4, 2019
98eb0ba
Remove unused import
eotin Apr 4, 2019
50f32e2
Merge pull request #47 from eotin/Develop
eotin Apr 4, 2019
32f5cd8
Fix tracking service test class
eotin Apr 4, 2019
d7a4545
Merge pull request #48 from eotin/Develop
eotin Apr 4, 2019
a07f0b7
Refactor string initialization
eotin Apr 4, 2019
a53398c
Refactor accessing to the storage from the TrackingService
eotin Apr 4, 2019
0481e56
Merge pull request #49 from eotin/Develop
eotin Apr 4, 2019
cc9c2a6
Increase Unit test coverage
eotin Apr 5, 2019
a5e259d
Merge pull request #50 from eotin/Develop
eotin Apr 5, 2019
ca63756
Add Check storage permissions
eotin Apr 5, 2019
b882843
Merge pull request #51 from eotin/Develop
eotin Apr 5, 2019
a11c5c0
Use KujakuMapView#updateDroppedPoints instead of modifying accessibil…
eotin Apr 5, 2019
23e155f
Merge pull request #52 from eotin/Develop
eotin Apr 5, 2019
884c8ce
Merge branch 'master' of https://github.com/onaio/kujaku
eotin Apr 8, 2019
f65e473
Merge pull request #54 from eotin/master
eotin Apr 8, 2019
5b4e234
Use MultiplePermissionsListener instead of PermissionListener in Kuja…
eotin Apr 9, 2019
cdaa51e
Merge remote-tracking branch 'origin/Develop' into Develop
eotin Apr 9, 2019
be6ccc9
Merge pull request #55 from eotin/Develop
eotin Apr 9, 2019
c46b690
Check if all permissions are granted too
eotin Apr 10, 2019
adae2d9
Fix TrackingService code after coding review
eotin Apr 10, 2019
7ad91c0
Merge pull request #56 from eotin/Develop
eotin Apr 10, 2019
13f2285
Add Comments in TrackingServiceTest
eotin Apr 11, 2019
bc1274c
Merge pull request #57 from eotin/Develop
eotin Apr 11, 2019
dce1b99
Add Comments in TrackingServiceTest
eotin Apr 11, 2019
e0b890d
Merge pull request #58 from eotin/Develop
eotin Apr 11, 2019
3c6d41f
Merge pull request #59 from onaio/master
eotin Apr 11, 2019
acb57fb
Merge pull request #60 from eotin/master
eotin Apr 11, 2019
32e841d
Make the TrackingService icon configurable
eotin Apr 11, 2019
532bebd
Merge pull request #61 from eotin/Develop
eotin Apr 11, 2019
5bb6db0
Make the TrackingService icon configurable
eotin Apr 12, 2019
3f7a462
Merge pull request #62 from eotin/Develop
eotin Apr 12, 2019
0bc8e75
Update kujaku_permission_reason string
eotin Apr 16, 2019
ce15819
Merge pull request #63 from eotin/Develop
eotin Apr 16, 2019
0a2bf67
Add method to unregister the tracking listener
eotin Apr 18, 2019
7ed98eb
Merge pull request #64 from eotin/Develop
eotin Apr 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions library/src/main/java/io/ona/kujaku/interfaces/IKujakuMapView.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* Created by Ephraim Kigamba - [email protected] on 26/09/2018
*/

import android.content.Context;
import android.location.Location;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
Expand All @@ -23,6 +25,8 @@
import io.ona.kujaku.listeners.BoundsChangeListener;
import io.ona.kujaku.listeners.LocationClientStartedCallback;
import io.ona.kujaku.listeners.OnFeatureClickListener;
import io.ona.kujaku.listeners.TrackingServiceListener;
import io.ona.kujaku.services.options.TrackingServiceOptions;

public interface IKujakuMapView extends IKujakuMapViewLowLevel {

Expand Down Expand Up @@ -257,4 +261,59 @@ public interface IKujakuMapView extends IKujakuMapViewLowLevel {
boolean isKujakuLayerAdded(@NonNull KujakuLayer kujakuLayer);

void removeLayer(@NonNull KujakuLayer kujakuLayer);


/**
* Start the instance of TrackingService that record filtered locations regarding the given {@link TrackingServiceOptions}
* You need to register a {@link TrackingServiceListener} to receive notifications as
* - {@link TrackingServiceListener#onFirstLocationReceived(Location)}
* - {@link TrackingServiceListener#onNewLocationReceived(Location)}
* - etc.
* The Class arguments is used to instantiate an activity when clicking the service notification
*
* @param context
* @param cls
* @param trackingServiceListener
* @param options
*/
void startTrackingService(@NonNull Context context, @NonNull Class<?> cls, @NonNull TrackingServiceListener trackingServiceListener, TrackingServiceOptions options);

/**
* Stop the instance of TrackingService
* It returns a collection of recorded Locations
*
* @param context
* @return
*/
List<Location> stopTrackingService(@NonNull Context context);

/**
* Unbind from the TrackingService instance to be able to stop the service
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. At this point our service life is not controlled by the binding idea
  2. Add the TrackingService link to the Table of Contents
  3. I would like to know how much you have tested the code in the field using the Kujaku sample app probably moving for more than 1 km. I am having unexpected results

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of unexpected results ? i have tested the kujaku sample multiple times during the itinerary between office and home and the passive activity shows me the exact route i have driven.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I walked out of the office to a Cafe and left the app as the foreground application and put it in my pocket. It recorded half my route. The route is recorded halfway there and from that point back.

Device is Android version 8.1.0

What android version did you test with?

Copy link
Contributor Author

@eotin eotin Apr 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok,There are some Android settings to modify :

  • You need to whitelist the sample application from the battery optimization. This is mandatory.
  • On some Huawei phones on Android 8.1, there is a new setting to modify : Settings->Battery->Launch->Managed Manually: Set the 3 Auto-launch, Secondary Launch, Run in Background

I tested the app with Android 8.1, 8.0, 7.0, 5.1

Copy link
Contributor

@ekigamba ekigamba Apr 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this worked and it recorded for 3 hours without a gap while using other applications.

Can you create that as an issue and we can also document it later for easy reference and troubleshooting? The issue will basically state that this has to be done manually and that documentation for how to do it is to be added using the issue. A different issue will address adding the ability to prompt the user to enable this from the following guidelines
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok make sense

*
* @param context
*/
void unBindTrackingService(@NonNull Context context);

/**
* This method can bind to an existing instance of the TrackingService already running
* You need to register a {@link TrackingServiceListener} to receive notifications
*
* @param context
* @param listener
* @return
*/
boolean resumeTrackingService(Context context, TrackingServiceListener listener);

/**
* This method force the TrackingService to take a location
*
*/
void trackingServiceTakeLocation();

/**
* This method returns the collection of recorded locations
*
* @return
*/
List<Location> getTrackingServiceRecordedLocations();
}
31 changes: 25 additions & 6 deletions library/src/main/java/io/ona/kujaku/services/TrackingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class TrackingService extends Service {
private volatile LocationManager locationManager;

private volatile Handler gpsHandler;
private Handler uiHandler;

private volatile Location lastRecordedLocation;
private volatile Location pendingRecordingLocation;
Expand Down Expand Up @@ -602,6 +603,9 @@ public void run() {
// You don't need to specify the Looper explicitly
gpsHandler = new Handler();

// Ui Handler
uiHandler = new Handler(Looper.getMainLooper());

// Register the Location listener
registerLocationListener();

Expand Down Expand Up @@ -666,7 +670,7 @@ protected void startServiceForeground() {

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, channel)
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.setContentTitle(getString(R.string.tracking_service_notification_title))
.setContentTitle(getString(R.string.app_name))
.setOngoing(true)
.setWhen(System.currentTimeMillis());

Expand Down Expand Up @@ -721,7 +725,12 @@ public void registerTrackingServiceListener(TrackingServiceListener listener) {
*/
private void informFirstLocationReceivedListener(Location location) {
if (this.trackingServiceListener != null && this.firstLocationReceived == null) {
trackingServiceListener.onFirstLocationReceived(location);
uiHandler.post(new Runnable() {
@Override
public void run() {
trackingServiceListener.onFirstLocationReceived(location);
}
});
this.firstLocationReceived = location ;
}
this.setServiceStatus(TrackingServiceStatus.WAITING_FIRST_RECORD);
Expand All @@ -734,7 +743,12 @@ private void informFirstLocationReceivedListener(Location location) {
*/
private void informNewTrackReceivedListener(Location location) {
if (this.trackingServiceListener != null && location != null) {
this.trackingServiceListener.onNewLocationReceived(location);
uiHandler.post(new Runnable() {
@Override
public void run() {
trackingServiceListener.onNewLocationReceived(location);
}
});
}
this.setServiceStatus(TrackingServiceStatus.RUNNING);
}
Expand All @@ -753,7 +767,12 @@ private void informCloseToDepartureLocationListener(Location location) {
Location departure = this.getFirstLocationRecorded();

if (departure != null && departure.distanceTo(location) <= trackingServiceOptions.getDistanceFromDeparture()) {
this.trackingServiceListener.onCloseToDepartureLocation(location);
uiHandler.post(new Runnable() {
@Override
public void run() {
trackingServiceListener.onCloseToDepartureLocation(location);
}
});
}
}
}
Expand Down Expand Up @@ -845,8 +864,8 @@ public static void startAndBindService(Context context, Class<?> cls, ServiceCon
* @param intent
* @param connection
*/
public static void bindService(Context context, Intent intent, ServiceConnection connection) {
context.bindService(intent, connection, BIND_AUTO_CREATE);
public static boolean bindService(Context context, Intent intent, ServiceConnection connection) {
return context.bindService(intent, connection, BIND_AUTO_CREATE);
}

/**
Expand Down
30 changes: 24 additions & 6 deletions library/src/main/java/io/ona/kujaku/views/KujakuMapView.java
Original file line number Diff line number Diff line change
Expand Up @@ -756,8 +756,6 @@ private void addMapScrollListenerAndBoundsChangeEmitterToMap(@NonNull MapboxMap
mapboxMap.addOnMoveListener(new MapboxMap.OnMoveListener() {
@Override
public void onMoveBegin(@NonNull MoveGestureDetector detector) {
// isMapScrolled = true;
// updateCameraUserLocationOnMap = false;
// We should assume the user no longer wants us to focus on their location
focusOnUserLocation(false);
}
Expand Down Expand Up @@ -857,6 +855,9 @@ public void onStop() {
locationClient.setListener(null);
locationClient = null;
}

// Unbind TrackingService if bound
this.unBindTrackingService(getContext());
}

@Override
Expand Down Expand Up @@ -1339,11 +1340,13 @@ public MapboxLocationComponentWrapper getMapboxLocationComponentWrapper() {
* @param context
* @param listener
*/
public void resumeTrackingService(Context context, TrackingServiceListener listener) {
public boolean resumeTrackingService(Context context, TrackingServiceListener listener) {
// TrackingService reconnection if connection was lost
if (! trackingServiceBound && TrackingService.isRunning()) {
this.trackingServiceListener = listener;
TrackingService.bindService(context, TrackingService.getIntent(context, null,null), connection);
return TrackingService.bindService(context, TrackingService.getIntent(context, null,null), connection);
} else {
return false;
}
}

Expand Down Expand Up @@ -1373,8 +1376,12 @@ public List<Location> stopTrackingService(@NonNull Context context) {
if (trackingServiceBound && trackingService != null) {
List<Location> locations = trackingService.getRecordedLocations();
TrackingService.stopAndUnbindService(context, connection);
trackingServiceBound = false;
trackingService = null ;
trackingServiceStatusButton.setImageResource(R.drawable.ic_recording_gray);
ekigamba marked this conversation as resolved.
Show resolved Hide resolved
return locations;
} else {
Log.d(TAG, "Tracking Service instance is null or not Tracking Service is not bounded");
}

return null;
Expand Down Expand Up @@ -1434,15 +1441,26 @@ public void onServiceConnected(ComponentName className,
trackingServiceStatusButton.setVisibility(VISIBLE);
trackingServiceStatusButton.setImageResource(R.drawable.ic_recording_red);

trackingServiceListener.onServiceConnected(trackingService);
((Activity)getContext()).runOnUiThread(new Runnable() {
@Override
public void run() {
trackingServiceListener.onServiceConnected(trackingService);
}
});
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
trackingServiceBound = false;
trackingService = null;
trackingServiceStatusButton.setImageResource(R.drawable.ic_recording_gray);
trackingServiceListener.onServiceDisconnected();

((Activity)getContext()).runOnUiThread(new Runnable() {
@Override
public void run() {
trackingServiceListener.onServiceDisconnected();
}
});
}
};

Expand Down
1 change: 0 additions & 1 deletion library/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
<string name="map_download_could_not_be_stopped">Map download could not be stopped</string>
<string name="location_service_disabled">Location service disabled</string>
<string name="location_service_disabled_dialog_explanation"><![CDATA[You will not be able to use the My Location feature in this app. To change this, go to Settings > Location]]></string>
<string name="tracking_service_notification_title">Kujaku Tracking service</string>
<string name="tracking_service_channel_name">Kujaku Tracking service channel</string>
<string name="tracking_service_channel_id">@string/tracking_service_channel_name</string>
</resources>
3 changes: 1 addition & 2 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".activities.PassiveRecordObjectActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleInstance"/>
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".activities.FociBoundaryActivity"
android:theme="@style/AppTheme.NoActionBar"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,32 +131,20 @@ public void onServiceConnected(TrackingService service) {

@Override
public void onFirstLocationReceived(Location location) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "First Location received", Toast.LENGTH_LONG).show();
}
});
Toast.makeText(getApplicationContext(), "First Location received", Toast.LENGTH_LONG).show();
}

@Override
public void onNewLocationReceived(Location location) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "New Location received", Toast.LENGTH_SHORT).show();
List<Point> points = new ArrayList<>();
points.add(new Point(location.hashCode(), location.getLatitude(), location.getLongitude()));
kujakuMapView.updateDroppedPoints(points);
}
});
Toast.makeText(getApplicationContext(), "New Location received", Toast.LENGTH_SHORT).show();
List<Point> points = new ArrayList<>();
points.add(new Point(location.hashCode(), location.getLatitude(), location.getLongitude()));
kujakuMapView.updateDroppedPoints(points);
}

@Override
public void onCloseToDepartureLocation(Location location) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Location recorded is closed to the departure location", Toast.LENGTH_LONG).show();
}
});
Toast.makeText(getApplicationContext(), "Location recorded is closed to the departure location", Toast.LENGTH_LONG).show();
}

/**** TrackingServiceListener END ****/
Expand Down Expand Up @@ -199,9 +187,6 @@ protected void onPause() {
protected void onDestroy() {
super.onDestroy();
if (kujakuMapView != null) kujakuMapView.onDestroy();

// Unbind Service to be sure we can stop the TrackingService
if (kujakuMapView != null) kujakuMapView.unBindTrackingService(getApplicationContext());
}

@Override
Expand Down