added iOS source code
[wl-app.git] / iOS / Pods / FirebaseMessaging / Firebase / Messaging / FIRMessagingContextManagerService.m
1 /*
2  * Copyright 2017 Google
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  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #import "FIRMessagingContextManagerService.h"
18
19 #import <UIKit/UIKit.h>
20
21 #import "FIRMessagingDefines.h"
22 #import "FIRMessagingLogger.h"
23 #import "FIRMessagingUtilities.h"
24
25 #define kFIRMessagingContextManagerPrefixKey @"google.c.cm."
26 #define kFIRMessagingContextManagerNotificationKeyPrefix @"gcm.notification."
27
28 static NSString *const kLogTag = @"FIRMessagingAnalytics";
29
30 static NSString *const kLocalTimeFormatString = @"yyyy-MM-dd HH:mm:ss";
31
32 static NSString *const kContextManagerPrefixKey = kFIRMessagingContextManagerPrefixKey;
33
34 // Local timed messages (format yyyy-mm-dd HH:mm:ss)
35 NSString *const kFIRMessagingContextManagerLocalTimeStart = kFIRMessagingContextManagerPrefixKey @"lt_start";
36 NSString *const kFIRMessagingContextManagerLocalTimeEnd = kFIRMessagingContextManagerPrefixKey @"lt_end";
37
38 // Local Notification Params
39 NSString *const kFIRMessagingContextManagerBodyKey = kFIRMessagingContextManagerNotificationKeyPrefix @"body";
40 NSString *const kFIRMessagingContextManagerTitleKey = kFIRMessagingContextManagerNotificationKeyPrefix @"title";
41 NSString *const kFIRMessagingContextManagerBadgeKey = kFIRMessagingContextManagerNotificationKeyPrefix @"badge";
42 NSString *const kFIRMessagingContextManagerCategoryKey =
43     kFIRMessagingContextManagerNotificationKeyPrefix @"click_action";
44 NSString *const kFIRMessagingContextManagerSoundKey = kFIRMessagingContextManagerNotificationKeyPrefix @"sound";
45 NSString *const kFIRMessagingContextManagerContentAvailableKey =
46     kFIRMessagingContextManagerNotificationKeyPrefix @"content-available";
47
48 typedef NS_ENUM(NSUInteger, FIRMessagingContextManagerMessageType) {
49   FIRMessagingContextManagerMessageTypeNone,
50   FIRMessagingContextManagerMessageTypeLocalTime,
51 };
52
53 @implementation FIRMessagingContextManagerService
54
55 + (BOOL)isContextManagerMessage:(NSDictionary *)message {
56   // For now we only support local time in ContextManager.
57   if (![message[kFIRMessagingContextManagerLocalTimeStart] length]) {
58     FIRMessagingLoggerDebug(kFIRMessagingMessageCodeContextManagerService000,
59                             @"Received message missing local start time, dropped.");
60     return NO;
61   }
62
63   return YES;
64 }
65
66 + (BOOL)handleContextManagerMessage:(NSDictionary *)message {
67   NSString *startTimeString = message[kFIRMessagingContextManagerLocalTimeStart];
68   if (startTimeString.length) {
69     FIRMessagingLoggerDebug(kFIRMessagingMessageCodeContextManagerService001,
70                             @"%@ Received context manager message with local time %@", kLogTag,
71                             startTimeString);
72     return [self handleContextManagerLocalTimeMessage:message];
73   }
74
75   return NO;
76 }
77
78 + (BOOL)handleContextManagerLocalTimeMessage:(NSDictionary *)message {
79   NSString *startTimeString = message[kFIRMessagingContextManagerLocalTimeStart];
80   NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
81   [dateFormatter setDateFormat:kLocalTimeFormatString];
82   NSDate *startDate = [dateFormatter dateFromString:startTimeString];
83
84   _FIRMessagingDevAssert(startDate, @"Invalid local start date format %@", startTimeString);
85   if (!startTimeString) {
86     FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerService002,
87                             @"Invalid local start date format %@. Message dropped",
88                             startTimeString);
89     return NO;
90   }
91
92   NSDate *currentDate = [NSDate date];
93
94   if ([currentDate compare:startDate] == NSOrderedAscending) {
95     [self scheduleLocalNotificationForMessage:message
96                                        atDate:startDate];
97   } else {
98     // check end time has not passed
99     NSString *endTimeString = message[kFIRMessagingContextManagerLocalTimeEnd];
100     if (!endTimeString) {
101       FIRMessagingLoggerInfo(
102           kFIRMessagingMessageCodeContextManagerService003,
103           @"No end date specified for message, start date elapsed. Message dropped.");
104       return YES;
105     }
106
107     NSDate *endDate = [dateFormatter dateFromString:endTimeString];
108
109     _FIRMessagingDevAssert(endDate, @"Invalid local end date format %@", endTimeString);
110     if (!endTimeString) {
111       FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerService004,
112                               @"Invalid local end date format %@. Message dropped", endTimeString);
113       return NO;
114     }
115
116     if ([endDate compare:currentDate] == NSOrderedAscending) {
117       // end date has already passed drop the message
118       FIRMessagingLoggerInfo(kFIRMessagingMessageCodeContextManagerService005,
119                              @"End date %@ has already passed. Message dropped.", endTimeString);
120       return YES;
121     }
122
123     // schedule message right now (buffer 10s)
124     [self scheduleLocalNotificationForMessage:message
125                                        atDate:[currentDate dateByAddingTimeInterval:10]];
126   }
127   return YES;
128 }
129
130 + (void)scheduleLocalNotificationForMessage:(NSDictionary *)message
131                                      atDate:(NSDate *)date {
132   NSDictionary *apsDictionary = message;
133 #pragma clang diagnostic push
134 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
135   UILocalNotification *notification = [[UILocalNotification alloc] init];
136 #pragma clang diagnostic pop
137
138   // A great way to understand timezones and UILocalNotifications
139   // http://stackoverflow.com/questions/18424569/understanding-uilocalnotification-timezone
140   notification.timeZone = [NSTimeZone defaultTimeZone];
141   notification.fireDate = date;
142
143   // In the current solution all of the display stuff goes into a special "aps" dictionary
144   // being sent in the message.
145   if ([apsDictionary[kFIRMessagingContextManagerBodyKey] length]) {
146     notification.alertBody = apsDictionary[kFIRMessagingContextManagerBodyKey];
147   }
148   if ([apsDictionary[kFIRMessagingContextManagerTitleKey] length]) {
149     // |alertTitle| is iOS 8.2+, so check if we can set it
150       if ([notification respondsToSelector:@selector(setAlertTitle:)]) {
151 #pragma clang diagnostic push
152 #pragma clang diagnostic ignored "-Wunguarded-availability"
153       notification.alertTitle = apsDictionary[kFIRMessagingContextManagerTitleKey];
154 #pragma pop
155     }
156   }
157
158   if (apsDictionary[kFIRMessagingContextManagerSoundKey]) {
159     notification.soundName = apsDictionary[kFIRMessagingContextManagerSoundKey];
160   }
161   if (apsDictionary[kFIRMessagingContextManagerBadgeKey]) {
162     notification.applicationIconBadgeNumber =
163         [apsDictionary[kFIRMessagingContextManagerBadgeKey] integerValue];
164   }
165   if (apsDictionary[kFIRMessagingContextManagerCategoryKey]) {
166     // |category| is iOS 8.0+, so check if we can set it
167     if ([notification respondsToSelector:@selector(setCategory:)]) {
168       notification.category = apsDictionary[kFIRMessagingContextManagerCategoryKey];
169     }
170   }
171
172   NSDictionary *userInfo = [self parseDataFromMessage:message];
173   if (userInfo.count) {
174     notification.userInfo = userInfo;
175   }
176 #pragma clang diagnostic push
177 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
178   UIApplication *application = FIRMessagingUIApplication();
179   if (!application) {
180     return;
181   }
182   [application scheduleLocalNotification:notification];
183 #pragma clang diagnostic pop
184 }
185
186 + (NSDictionary *)parseDataFromMessage:(NSDictionary *)message {
187   NSMutableDictionary *data = [NSMutableDictionary dictionary];
188   for (NSObject<NSCopying> *key in message) {
189     if ([key isKindOfClass:[NSString class]]) {
190       NSString *keyString = (NSString *)key;
191       if ([keyString isEqualToString:kFIRMessagingContextManagerContentAvailableKey]) {
192         continue;
193       } else if ([keyString hasPrefix:kContextManagerPrefixKey]) {
194         continue;
195       }
196     }
197     data[[key copy]] = message[key];
198   }
199   return [data copy];
200 }
201
202 @end