-
Notifications
You must be signed in to change notification settings - Fork 0
/
tasks.ts
151 lines (138 loc) · 5.57 KB
/
tasks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { LocationObject } from 'expo-location';
import { insideGeoFences } from './helpers/geoFenceCalculations';
import {
readLocationEvents,
readPushToken,
storeLocationEvents,
LocationEvent,
readTrackingInfo,
readGeoFences,
updatePreviousOutsideGeofencePushTimestamp,
readPreviousOutsideGeofencePushTimestamp,
readPreviousInsideGeofencePush,
storePreviousInsideGeofencePush,
} from './helpers/storage';
import { sendPushNotification } from './helpers/pushNotifications';
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
import * as Location from 'expo-location';
import * as Analytics from 'expo-firebase-analytics';
import Constants from 'expo-constants';
export const LOCATION_BACKGROUND_TRACKING = 'location-background-tracking';
export const NOTIFICATION_WHEN_INSIDE_GEOFENCE = 'notification-when-inside-geofence';
TaskManager.defineTask(LOCATION_BACKGROUND_TRACKING, async ({ data, error }) => {
if (error) {
console.error('LOCATION_BACKGROUND_TRACKING: ', error.message);
return;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const anyData: any = data;
if (anyData.locations) {
const currentLocation: LocationObject = anyData.locations[0];
const trackingInfo = await readTrackingInfo();
if (!trackingInfo.geoFence) {
console.error('LOCATION_BACKGROUND_TRACKING: No geofence present in storage.');
return;
}
// Locations with timestamp before tracking started should be discarded
if (currentLocation.timestamp < trackingInfo.startTimestamp) return;
const insideGeoFence = insideGeoFences(currentLocation, [trackingInfo.geoFence]);
const trackingLocations = await readLocationEvents();
if (!insideGeoFence) {
// If tracking accuracy is poor, we should not treat it as an "Out of geofence event"
if (currentLocation.coords.accuracy && currentLocation.coords.accuracy < 10) return;
if (trackingLocations.length === 0) {
const location: LocationEvent = {
location: currentLocation,
insideGeofence: false,
};
storeLocationEvents([location]);
return;
}
const lastStoredLocation = trackingLocations[trackingLocations.length - 1];
if (lastStoredLocation.insideGeofence === true) {
console.log('Background location event: Moved out of geofence.');
const location: LocationEvent = {
location: currentLocation,
insideGeofence: false,
};
storeLocationEvents([...trackingLocations, location]);
if (Constants.isDevice) {
const pushToken = await readPushToken();
const previousPushUpdate = await readPreviousOutsideGeofencePushTimestamp();
// Send push notification if it is more than 5 minutes since previous "Outside geofence" push notification was sent.
if ((pushToken && !previousPushUpdate) || (pushToken && previousPushUpdate < Date.now() - 5 * 60 * 1000)) {
sendPushNotification(
pushToken,
'Oh noo!😯 You are outside the Hover zone...',
'Move back in to continue earning points. ' +
'Tracking will start automagically when you are inside the Hover zone.',
true,
true,
);
updatePreviousOutsideGeofencePushTimestamp();
}
}
}
} else {
if (trackingLocations.length === 0) {
const location: LocationEvent = {
location: currentLocation,
insideGeofence: true,
};
storeLocationEvents([location]);
return;
}
const lastStoredLocation = trackingLocations[trackingLocations.length - 1];
if (lastStoredLocation.insideGeofence === false) {
console.log('Background location event: Moved back in to geofence.');
const location: LocationEvent = {
location: currentLocation,
insideGeofence: true,
};
storeLocationEvents([...trackingLocations, location]);
}
}
}
});
TaskManager.defineTask(NOTIFICATION_WHEN_INSIDE_GEOFENCE, async () => {
console.log('Background fetch task running');
const geoFences = await readGeoFences();
if (geoFences.length > 0) {
const currentLocation = await Location.getCurrentPositionAsync({});
const insideGeoFence = insideGeoFences(currentLocation, geoFences);
if (insideGeoFence) {
const trackingLocations = await readLocationEvents();
if (trackingLocations.length === 0) {
// Not currently tracking
const previousInsideGeofencePush = await readPreviousInsideGeofencePush();
if (
!previousInsideGeofencePush ||
insideGeoFence.id !== previousInsideGeofencePush.geoFenceId ||
previousInsideGeofencePush.timestamp < Date.now() - 60 * 60 * 12 * 1000
) {
const pushToken = await readPushToken();
if (pushToken) {
sendPushNotification(
pushToken,
'Hi there!👋 I see you are inside a Hover zone',
'Do you want to start tracking?',
true,
false,
);
storePreviousInsideGeofencePush(insideGeoFence.id);
Analytics.logEvent('PN_inside_geofence_sent', {
event: 'sent',
purpose: 'User open push notification.',
});
return BackgroundFetch.Result.NewData;
}
}
return BackgroundFetch.Result.NoData;
}
return BackgroundFetch.Result.NoData;
}
return BackgroundFetch.Result.NoData;
}
return BackgroundFetch.Result.Failed;
});