Skip to content

Commit acf6d6a

Browse files
Merge pull request #2294 from aws-amplify/geo-mobileconnector
feat(location): Add Amazon Location high level client
2 parents 16ac400 + fc9fd08 commit acf6d6a

19 files changed

+1362
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apply from: rootProject.file('publishing.gradle')
2+
apply plugin: 'com.android.library'
3+
4+
android {
5+
compileSdkVersion 30
6+
7+
defaultConfig {
8+
minSdkVersion 9
9+
targetSdkVersion 30
10+
}
11+
}
12+
13+
dependencies {
14+
api project(':aws-android-sdk-core')
15+
implementation 'androidx.annotation:annotation:1.1.0'
16+
implementation 'com.google.android.gms:play-services-location:17.0.0'
17+
18+
testImplementation 'commons-logging:commons-logging:1.2'
19+
testImplementation 'junit:junit:4.13.1'
20+
testImplementation 'org.apache.commons:commons-io:1.3.2'
21+
testImplementation 'org.hamcrest:hamcrest:2.2'
22+
testImplementation 'org.mockito:mockito-all:1.10.19'
23+
testImplementation 'org.robolectric:robolectric:4.4'
24+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
POM_ARTIFACT_ID=aws-android-sdk-location
2+
POM_DESCRIPTION=The AWS Android SDK for Amazon Location module holds the client classes that are used for communicating with Amazon Location Service
3+
POM_NAME=AWS SDK for Android - Amazon Location
4+
POM_PACKAGING=aar
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
package="com.amazonaws.services.geo">
5+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6+
7+
<application>
8+
<service
9+
android:name="com.amazonaws.mobileconnectors.geo.tracker.TrackingService"
10+
android:enabled="true"
11+
android:exported="true"
12+
android:foregroundServiceType="location" />
13+
</application>
14+
</manifest>
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amazonaws.mobileconnectors.geo.tracker;
17+
18+
import android.content.ComponentName;
19+
import android.content.Context;
20+
import android.content.Intent;
21+
import android.content.ServiceConnection;
22+
import android.content.SharedPreferences;
23+
import android.location.Location;
24+
import android.os.IBinder;
25+
import android.util.Log;
26+
27+
import androidx.annotation.NonNull;
28+
29+
import com.amazonaws.ClientConfiguration;
30+
import com.amazonaws.auth.AWSCredentialsProvider;
31+
import com.amazonaws.services.geo.AmazonLocationClient;
32+
33+
import java.util.UUID;
34+
import java.util.concurrent.TimeUnit;
35+
import java.util.concurrent.atomic.AtomicBoolean;
36+
37+
/**
38+
* Monitor your device's location and periodically send the tracked coordinates to the Amazon Location Service.
39+
*/
40+
public class AWSLocationTracker {
41+
private static final String TAG = AWSLocationTracker.class.getSimpleName();
42+
public static final Long DEFAULT_RETRIEVE_LOCATION_FREQUENCY = TimeUnit.SECONDS.toMillis(30);
43+
public static final Long DEFAULT_EMIT_LOCATION_FREQUENCY = TimeUnit.MINUTES.toMillis(5);
44+
private static final String DEFAULT_DEVICE_ID_KEY = "AWSLocationTrackerDeviceId";
45+
private AtomicBoolean isTracking;
46+
private String deviceId;
47+
private TrackingListener listener;
48+
private TrackingOptions options;
49+
private TrackingService trackingService;
50+
private TrackingPublisher trackingPublisher;
51+
private final String trackerName;
52+
private final AWSCredentialsProvider credentialsProvider;
53+
private final AmazonLocationClient locationClient;
54+
55+
private final ServiceConnection serviceConnection = new ServiceConnection() {
56+
@Override
57+
public void onServiceConnected(ComponentName name, IBinder service) {
58+
Log.d(TAG, "ServiceConnection onServiceConnected triggered.");
59+
TrackingService.LocalBinder binder = (TrackingService.LocalBinder) service;
60+
trackingService = binder.getService();
61+
trackingService.startLocationUpdates(
62+
options.getRetrieveLocationFrequency() == null ?
63+
DEFAULT_RETRIEVE_LOCATION_FREQUENCY :
64+
options.getRetrieveLocationFrequency(),
65+
new TrackingServiceListener() {
66+
@Override
67+
public void onLocationReceived(Location location) {
68+
trackingPublisher.enqueue(location);
69+
}
70+
71+
@Override
72+
public void onError(TrackingError exception) {
73+
listener.onDataPublicationError(exception);
74+
}
75+
}
76+
);
77+
78+
isTracking.set(true);
79+
}
80+
81+
/**
82+
* This only gets triggered if the service process crashes. It
83+
* does not get invoked when unbind is called for the last client
84+
* connected to the service.
85+
* @param name
86+
*/
87+
@Override
88+
public void onServiceDisconnected(ComponentName name) {
89+
Log.d(TAG, "ServiceConnection onServiceDisconnected triggered.");
90+
stopTracking();
91+
}
92+
};
93+
94+
/**
95+
* Create a new tracker instance.
96+
* @param trackerName The name of your tracker resource.
97+
* @param credentialsProvider Your auth provider - most likely AWSMobileClient.getInstance()
98+
*/
99+
public AWSLocationTracker(
100+
@NonNull String trackerName,
101+
@NonNull AWSCredentialsProvider credentialsProvider) {
102+
this.trackerName = trackerName;
103+
this.credentialsProvider = credentialsProvider;
104+
this.isTracking = new AtomicBoolean(false);
105+
this.locationClient = new AmazonLocationClient(credentialsProvider, new ClientConfiguration());
106+
}
107+
108+
/**
109+
* Start monitoring your device's location and sending the tracked coordinates to Amazon Location Service.
110+
* @param context Context for the application you are calling this from
111+
*/
112+
public void startTracking(@NonNull Context context) {
113+
startTracking(context, TrackingOptions.builder().build(), new EmptyTrackingListener());
114+
}
115+
116+
/**
117+
* Start monitoring your device's location and sending the tracked coordinates to Amazon Location Service.
118+
* @param context Context for the application you are calling this from
119+
* @param listener Contains the various callback methods to listen to the different events which will be emitted.
120+
*/
121+
public void startTracking(
122+
@NonNull Context context,
123+
@NonNull TrackingListener listener) {
124+
startTracking(context, TrackingOptions.builder().build(), listener);
125+
}
126+
127+
/**
128+
* Start monitoring your device's location and sending the tracked coordinates to Amazon Location Service.
129+
* @param context Context for the application you are calling this from
130+
* @param options Configure details of how tracking will work.
131+
* @param listener Contains the various callback methods to listen to the different events which will be emitted.
132+
*/
133+
public synchronized void startTracking(
134+
@NonNull Context context,
135+
@NonNull TrackingOptions options,
136+
@NonNull TrackingListener listener) {
137+
if (isTracking()) {
138+
throw new RuntimeException("Location tracker already started.");
139+
}
140+
this.deviceId = options.getCustomDeviceId() == null ?
141+
getDefaultDeviceId(context) : options.getCustomDeviceId();
142+
this.listener = listener;
143+
this.options = options;
144+
this.trackingPublisher = new TrackingPublisher(
145+
locationClient,
146+
deviceId,
147+
5,
148+
options.getEmitLocationFrequency() == null ?
149+
DEFAULT_EMIT_LOCATION_FREQUENCY :
150+
options.getEmitLocationFrequency(),
151+
10,
152+
listener);
153+
154+
context.bindService(new Intent(context, TrackingService.class), serviceConnection,
155+
Context.BIND_AUTO_CREATE);
156+
}
157+
158+
/**
159+
* Stop recording and sending the device's location. You can start tracking again with new options if you want.
160+
*/
161+
public synchronized void stopTracking(@NonNull Context context) {
162+
if (isTracking()) {
163+
context.unbindService(serviceConnection);
164+
// Since onServiceDisconnected on gets called if the service crashes, we need to shutdown the
165+
// tracking processes from here as well. Simply unbinding doesn't trigger onServiceDisconnected (see above)
166+
stopTracking();
167+
}
168+
}
169+
170+
/**
171+
* Returns true if this tracker instance is currently monitoring and sending the device's location. False otherwise.
172+
* @return true if this tracker instance is currently monitoring and sending the device's location. False otherwise.
173+
*/
174+
public synchronized boolean isTracking() {
175+
return this.isTracking.get();
176+
}
177+
178+
private void stopTracking() {
179+
if (trackingService != null && trackingPublisher != null) {
180+
trackingService.stopLocationUpdates();
181+
trackingPublisher.shutdown();
182+
trackingPublisher = null;
183+
trackingService = null;
184+
isTracking.set(false);
185+
listener.onStop();
186+
}
187+
}
188+
189+
private String getDefaultDeviceId(Context context) {
190+
SharedPreferences sharedPreferences = context.getSharedPreferences(DEFAULT_DEVICE_ID_KEY, Context.MODE_PRIVATE);
191+
String uniqueID = sharedPreferences != null ?
192+
sharedPreferences.getString(DEFAULT_DEVICE_ID_KEY, null) : null;
193+
194+
if (uniqueID == null && sharedPreferences != null) {
195+
uniqueID = UUID.randomUUID().toString();
196+
SharedPreferences.Editor editor = sharedPreferences.edit();
197+
editor.putString(DEFAULT_DEVICE_ID_KEY, uniqueID);
198+
editor.apply();
199+
}
200+
201+
return uniqueID;
202+
}
203+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.amazonaws.mobileconnectors.geo.tracker;
2+
3+
/**
4+
* Empty implementation of Tracking Listener used as a placeholder if the user doesn't care about receiving events.
5+
*/
6+
public class EmptyTrackingListener implements TrackingListener {
7+
@Override
8+
public void onStop() {}
9+
10+
@Override
11+
public void onDataPublished(TrackingPublishedEvent event) {}
12+
13+
@Override
14+
public void onDataPublicationError(TrackingError error) {}
15+
}

0 commit comments

Comments
 (0)