Skip to content

Commit cc8bcb4

Browse files
committed
Merge remote-tracking branch 'origin/dev' into diy-sync
2 parents c142386 + 49412b6 commit cc8bcb4

26 files changed

+973
-190
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ script:
1717
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme Loop build CODE_SIGN_IDENTITY="" CODE_SIGNING_ALLOWED=NO | xcpretty
1818
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme Learn build CODE_SIGN_IDENTITY="" CODE_SIGNING_ALLOWED=NO | xcpretty
1919
# Run the test target
20-
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme LoopTests -destination 'name=iPhone 6' test | xcpretty
21-
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme DoseMathTests -destination 'name=iPhone 6' test | xcpretty
20+
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme LoopTests -destination 'name=iPhone 8' test | xcpretty
21+
- set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme DoseMathTests -destination 'name=iPhone 8' test | xcpretty

Cartfile.resolved

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github "LoopKit/Amplitude-iOS" "2137d5fd44bf630ed33e1e72d7af6d8f8612f270"
2-
github "LoopKit/CGMBLEKit" "7417605dd898bf89378171941126c85d85dc642c"
2+
github "LoopKit/CGMBLEKit" "8983147b950a21f736c3e51c1e5ac5c82a6e22d0"
33
github "LoopKit/G4ShareSpy" "e62d296067180c6659166272ff9cc406f470ec9e"
4-
github "LoopKit/LoopKit" "18a5a04afd310e945ac54f8c43a44838a16503c2"
4+
github "LoopKit/LoopKit" "c49025f74aa22845eec58546d4b00f189632246b"
55
github "LoopKit/MKRingProgressView" "f548a5c64832be2d37d7c91b5800e284887a2a0a"
66
github "LoopKit/dexcom-share-client-swift" "c4f3d48e56e5b3ad786486ccd1bbc753034096d2"
77
github "i-schuetz/SwiftCharts" "0.6.5"
8-
github "ps2/rileylink_ios" "4e37d82e45f87d239bbd160ceacb5eca50d0336e"
8+
github "ps2/rileylink_ios" "3082367b3484586cd3a70a7134edef3ea35c6b9b"

Loop.xcodeproj/project.pbxproj

Lines changed: 36 additions & 10 deletions
Large diffs are not rendered by default.

Loop/AppDelegate.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
3131
SharedLogging.instance = deviceManager.loggingServicesManager
3232

3333
NotificationManager.authorize(delegate: self)
34-
34+
3535
log.info(#function)
3636

3737
deviceManager.analyticsServicesManager.application(application, didFinishLaunchingWithOptions: launchOptions)
3838

3939
rootViewController.rootViewController.deviceManager = deviceManager
40+
41+
let notificationOption = launchOptions?[.remoteNotification]
42+
43+
if let notification = notificationOption as? [String: AnyObject] {
44+
deviceManager.handleRemoteNotification(notification)
45+
}
4046

4147
return true
4248
}
@@ -79,6 +85,32 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
7985
return false
8086
}
8187
}
88+
89+
// MARK: - Remote notifications
90+
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
91+
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
92+
let token = tokenParts.joined()
93+
log.default("RemoteNotifications device token: \(token)")
94+
deviceManager.loopManager.settings.deviceToken = deviceToken
95+
}
96+
97+
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
98+
log.error("Failed to register: \(error)")
99+
}
100+
101+
func application(_ application: UIApplication,
102+
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
103+
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
104+
) {
105+
guard let notification = userInfo as? [String: AnyObject] else {
106+
completionHandler(.failed)
107+
return
108+
}
109+
110+
deviceManager.handleRemoteNotification(notification)
111+
completionHandler(.noData)
112+
}
113+
82114
}
83115

84116

@@ -111,4 +143,5 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
111143
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
112144
completionHandler([.badge, .sound, .alert])
113145
}
146+
114147
}

Loop/Info.plist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<key>UIBackgroundModes</key>
6363
<array>
6464
<string>bluetooth-central</string>
65+
<string>remote-notification</string>
6566
</array>
6667
<key>UILaunchStoryboardName</key>
6768
<string>LaunchScreen</string>

Loop/Loop.entitlements

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>aps-environment</key>
6+
<string>development</string>
57
<key>com.apple.developer.healthkit</key>
68
<true/>
79
<key>com.apple.developer.healthkit.access</key>

Loop/Managers/AnalyticsServicesManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ final class AnalyticsServicesManager {
139139
logEvent("CGM Fetch", outOfSession: true)
140140
}
141141

142-
func loopDidSucceed() {
143-
logEvent("Loop success", outOfSession: true)
142+
func loopDidSucceed(_ duration: TimeInterval) {
143+
logEvent("Loop success", withProperties: ["duration": duration], outOfSession: true)
144144
}
145145

146146
func loopDidError() {

Loop/Managers/DeviceDataManager.swift

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ final class DeviceDataManager {
3030
/// Should be accessed only on the main queue
3131
private(set) var lastError: (date: Date, error: Error)?
3232

33-
/// The last time a BLE heartbeat was received by the pump manager
33+
/// The last time a BLE heartbeat was received and acted upon.
3434
private var lastBLEDrivenUpdate = Date.distantPast
3535

3636
// MARK: - CGM
@@ -157,6 +157,40 @@ final class DeviceDataManager {
157157

158158
return Manager.init(rawState: rawState) as? PumpManagerUI
159159
}
160+
161+
private func processCGMResult(_ manager: CGMManager, result: CGMResult) {
162+
switch result {
163+
case .newData(let values):
164+
log.default("CGMManager:\(type(of: manager)) did update with \(values.count) values")
165+
166+
loopManager.addGlucose(values) { result in
167+
if manager.shouldSyncToRemoteService {
168+
switch result {
169+
case .success(let values):
170+
self.nightscoutDataManager.uploadGlucose(values, sensorState: manager.sensorState)
171+
case .failure:
172+
break
173+
}
174+
}
175+
176+
self.log.default("Asserting current pump data")
177+
self.pumpManager?.assertCurrentPumpData()
178+
}
179+
case .noData:
180+
log.default("CGMManager:\(type(of: manager)) did update with no data")
181+
182+
pumpManager?.assertCurrentPumpData()
183+
case .error(let error):
184+
log.default("CGMManager:\(type(of: manager)) did update with error: \(error)")
185+
186+
self.setLastError(error: error)
187+
log.default("Asserting current pump data")
188+
pumpManager?.assertCurrentPumpData()
189+
}
190+
191+
updatePumpManagerBLEHeartbeatPreference()
192+
}
193+
160194

161195
var availableCGMManagers: [AvailableDevice] {
162196
return pluginManager.availableCGMManagers + availableStaticCGMManagers
@@ -294,36 +328,8 @@ extension DeviceDataManager: CGMManagerDelegate {
294328

295329
func cgmManager(_ manager: CGMManager, didUpdateWith result: CGMResult) {
296330
dispatchPrecondition(condition: .onQueue(queue))
297-
switch result {
298-
case .newData(let values):
299-
log.default("CGMManager:%{public}@ did update with %d values", String(describing: type(of: manager)), values.count)
300-
301-
loopManager.addGlucose(values) { result in
302-
if manager.shouldSyncToRemoteService {
303-
switch result {
304-
case .success(let values):
305-
self.remoteDataServicesManager.upload(glucoseValues: values, sensorState: manager.sensorState)
306-
case .failure:
307-
break
308-
}
309-
}
310-
311-
self.log.default("Asserting current pump data")
312-
self.pumpManager?.assertCurrentPumpData()
313-
}
314-
case .noData:
315-
log.default("CGMManager:%{public}@ did update with no data", String(describing: type(of: manager)))
316-
317-
pumpManager?.assertCurrentPumpData()
318-
case .error(let error):
319-
log.default("CGMManager:%{public}@ did update with error: %{public}@", String(describing: type(of: manager)), String(describing: error))
320-
321-
self.setLastError(error: error)
322-
log.default("Asserting current pump data")
323-
pumpManager?.assertCurrentPumpData()
324-
}
325-
326-
updatePumpManagerBLEHeartbeatPreference()
331+
lastBLEDrivenUpdate = Date()
332+
processCGMResult(manager, result: result);
327333
}
328334

329335
func startDateToFilterNewData(for manager: CGMManager) -> Date? {
@@ -377,7 +383,11 @@ extension DeviceDataManager: PumpManagerDelegate {
377383
bleHeartbeatUpdateInterval = .minutes(1)
378384
case let interval?:
379385
// If we looped successfully less than 5 minutes ago, ignore the heartbeat.
386+
<<<<<<< HEAD
380387
log.default("PumpManager:%{public}@ ignoring heartbeat. Last loop completed %{public}@ minutes ago", String(describing: type(of: pumpManager)), String(describing: interval.minutes))
388+
=======
389+
log.default("PumpManager:\(type(of: pumpManager)) ignoring pumpManager heartbeat. Last loop completed \(-interval.minutes) minutes ago")
390+
>>>>>>> origin/dev
381391
return
382392
}
383393

@@ -394,7 +404,7 @@ extension DeviceDataManager: PumpManagerDelegate {
394404

395405
if let manager = self.cgmManager {
396406
self.queue.async {
397-
self.cgmManager(manager, didUpdateWith: result)
407+
self.processCGMResult(manager, result: result)
398408
}
399409
}
400410
}
@@ -671,3 +681,22 @@ extension Notification.Name {
671681
static let PumpManagerChanged = Notification.Name(rawValue: "com.loopKit.notification.PumpManagerChanged")
672682
static let PumpEventsAdded = Notification.Name(rawValue: "com.loopKit.notification.PumpEventsAdded")
673683
}
684+
685+
// MARK: - Remote Notification Handling
686+
extension DeviceDataManager {
687+
func handleRemoteNotification(_ notification: [String: AnyObject]) {
688+
689+
if let command = RemoteCommand(notification: notification, allowedPresets: loopManager.settings.overridePresets) {
690+
switch command {
691+
case .temporaryScheduleOverride(let override):
692+
log.default("Enacting remote temporary override: \(override)")
693+
loopManager.settings.scheduleOverride = override
694+
case .cancelTemporaryOverride:
695+
log.default("Canceling temporary override from remote command")
696+
loopManager.settings.scheduleOverride = nil
697+
}
698+
} else {
699+
log.info("Unhandled remote notification: \(notification)")
700+
}
701+
}
702+
}

Loop/Managers/LoopDataManager.swift

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ final class LoopDataManager {
9494
// Observe changes
9595
notificationObservers = [
9696
NotificationCenter.default.addObserver(
97-
forName: .CarbEntriesDidUpdate,
97+
forName: CarbStore.carbEntriesDidUpdate,
9898
object: carbStore,
9999
queue: nil
100100
) { (note) -> Void in
@@ -107,7 +107,7 @@ final class LoopDataManager {
107107
}
108108
},
109109
NotificationCenter.default.addObserver(
110-
forName: .GlucoseSamplesDidChange,
110+
forName: GlucoseStore.glucoseSamplesDidChange,
111111
object: glucoseStore,
112112
queue: nil
113113
) { (note) in
@@ -219,6 +219,8 @@ final class LoopDataManager {
219219
private let lockedBasalDeliveryState: Locked<PumpManagerStatus.BasalDeliveryState?>
220220

221221
fileprivate var lastRequestedBolus: DoseEntry?
222+
223+
private var lastLoopStarted: Date?
222224

223225
/// The last date at which a loop completed, from prediction to dose (if dosing is enabled)
224226
var lastLoopCompleted: Date? {
@@ -227,11 +229,6 @@ final class LoopDataManager {
227229
}
228230
set {
229231
lockedLastLoopCompleted.value = newValue
230-
231-
NotificationManager.clearLoopNotRunningNotifications()
232-
NotificationManager.scheduleLoopNotRunningNotifications()
233-
analyticsServicesManager.loopDidSucceed()
234-
NotificationCenter.default.post(name: .LoopCompleted, object: self)
235232
}
236233
}
237234
private let lockedLastLoopCompleted: Locked<Date?>
@@ -272,6 +269,15 @@ final class LoopDataManager {
272269
backgroundTask = .invalid
273270
}
274271
}
272+
273+
private func loopDidComplete(date: Date, duration: TimeInterval) {
274+
lastLoopCompleted = date
275+
NotificationManager.clearLoopNotRunningNotifications()
276+
NotificationManager.scheduleLoopNotRunningNotifications()
277+
AnalyticsManager.shared.loopDidSucceed(duration)
278+
NotificationCenter.default.post(name: .LoopCompleted, object: self)
279+
280+
}
275281
}
276282

277283
// MARK: Background task management
@@ -638,6 +644,7 @@ extension LoopDataManager {
638644
NotificationCenter.default.post(name: .LoopRunning, object: self)
639645

640646
self.lastLoopError = nil
647+
let startDate = Date()
641648

642649
do {
643650
try self.update()
@@ -649,7 +656,7 @@ extension LoopDataManager {
649656
if let error = error {
650657
self.logger.error("%{public}@", String(describing: error))
651658
} else {
652-
self.lastLoopCompleted = Date()
659+
self.loopDidComplete(date: Date(), duration: -startDate.timeIntervalSinceNow)
653660
}
654661
self.logger.default("Loop ended")
655662
self.notify(forChange: .tempBasal)
@@ -658,7 +665,7 @@ extension LoopDataManager {
658665
// Delay the notification until we know the result of the temp basal
659666
return
660667
} else {
661-
self.lastLoopCompleted = Date()
668+
self.loopDidComplete(date: Date(), duration: -startDate.timeIntervalSinceNow)
662669
}
663670
} catch let error {
664671
self.lastLoopError = error

Loop/Managers/NotificationManager.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,18 @@ struct NotificationManager {
5959

6060
let center = UNUserNotificationCenter.current()
6161
center.delegate = delegate
62-
center.requestAuthorization(options: authOptions, completionHandler: { _, _ in })
62+
center.requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in
63+
guard granted else { return }
64+
UNUserNotificationCenter.current().getNotificationSettings { settings in
65+
guard settings.authorizationStatus == .authorized else { return }
66+
DispatchQueue.main.async {
67+
UIApplication.shared.registerForRemoteNotifications()
68+
}
69+
}
70+
}
6371
center.setNotificationCategories(notificationCategories)
6472
}
73+
6574

6675
// MARK: - Notifications
6776

0 commit comments

Comments
 (0)