@@ -102,6 +102,7 @@ @interface ADJActivityHandler()
102102@property (nonatomic , copy ) ADJConfig *adjustConfig;
103103@property (nonatomic , copy ) NSData * deviceTokenData;
104104@property (nonatomic , copy ) NSString * basePath;
105+ @property (nonatomic , copy ) NSString * gdprPath;
105106
106107@end
107108
@@ -192,6 +193,9 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig
192193 if (savedPreLaunch.basePath != nil ) {
193194 self.basePath = savedPreLaunch.basePath ;
194195 }
196+ if (savedPreLaunch.gdprPath != nil ) {
197+ self.gdprPath = savedPreLaunch.gdprPath ;
198+ }
195199
196200 self.internalQueue = dispatch_queue_create (kInternalQueueName , DISPATCH_QUEUE_SERIAL);
197201 [ADJUtil launchInQueue: self .internalQueue
@@ -201,11 +205,12 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig
201205 preLaunchActionsArray: savedPreLaunch.preLaunchActionsArray];
202206 }];
203207
204-
208+ /* Not needed, done already in initI:preLaunchActionsArray: method.
205209 // self.deviceTokenData = savedPreLaunch.deviceTokenData;
206210 if (self.activityState != nil) {
207211 [self setDeviceToken:[ADJUserDefaults getPushToken]];
208212 }
213+ */
209214
210215 [self addNotificationObserver ];
211216
@@ -330,6 +335,10 @@ - (BOOL)isEnabled {
330335 return [self isEnabledI: self ];
331336}
332337
338+ - (BOOL )isGdprForgotten {
339+ return [self isGdprForgottenI: self ];
340+ }
341+
333342- (NSString *)adid {
334343 if (self.activityState == nil ) {
335344 return nil ;
@@ -353,6 +362,23 @@ - (void)setDeviceToken:(NSData *)deviceToken {
353362 }];
354363}
355364
365+ - (void )setGdprForgetMe {
366+ [ADJUtil launchInQueue: self .internalQueue
367+ selfInject: self
368+ block: ^(ADJActivityHandler * selfI) {
369+ [selfI setGdprForgetMeI: selfI];
370+ }];
371+ }
372+
373+ - (void )setTrackingStateOptedOut {
374+ [ADJUtil launchInQueue: self .internalQueue
375+ selfInject: self
376+ block: ^(ADJActivityHandler * selfI) {
377+ [selfI setTrackingStateOptedOutI: selfI];
378+ }];
379+ }
380+
381+
356382- (void )setAttributionDetails : (NSDictionary *)attributionDetails
357383 error : (NSError *)error
358384 retriesLeft : (int )retriesLeft
@@ -532,6 +558,10 @@ - (NSString *)getBasePath {
532558 return _basePath;
533559}
534560
561+ - (NSString *)getGdprPath {
562+ return _gdprPath;
563+ }
564+
535565- (void )teardown
536566{
537567 [ADJAdjustFactory.logger verbose: @" ADJActivityHandler teardown" ];
@@ -635,11 +665,16 @@ - (void)initI:(ADJActivityHandler *)selfI
635665 } else {
636666 if (selfI.activityState != nil ) {
637667 NSData *deviceToken = [ADJUserDefaults getPushToken ];
638-
639668 [selfI setDeviceToken: deviceToken];
640669 }
641670 }
642671
672+ if (selfI.activityState != nil ) {
673+ if ([ADJUserDefaults getGdprForgetMe ]) {
674+ [selfI setGdprForgetMe ];
675+ }
676+ }
677+
643678 selfI.foregroundTimer = [ADJTimerCycle timerWithBlock: ^{
644679 [selfI foregroundTimerFired ];
645680 }
@@ -737,8 +772,13 @@ - (void)processSessionI:(ADJActivityHandler *)selfI {
737772
738773 // track the first session package only if it's enabled
739774 if ([selfI.internalState isEnabled ]) {
740- selfI.activityState .sessionCount = 1 ; // this is the first session
741- [selfI transferSessionPackageI: selfI now: now];
775+ // If user chose to be forgotten before install has ever tracked, don't track it.
776+ if (![ADJUserDefaults getGdprForgetMe ]) {
777+ selfI.activityState .sessionCount = 1 ; // this is the first session
778+ [selfI transferSessionPackageI: selfI now: now];
779+ } else {
780+ [selfI setGdprForgetMeI: selfI];
781+ }
742782 }
743783
744784 [selfI.activityState resetSessionAttributes: now];
@@ -781,11 +821,13 @@ - (void)processSessionI:(ADJActivityHandler *)selfI {
781821}
782822
783823- (void )trackNewSessionI : (double )now withActivityHandler : (ADJActivityHandler *)selfI {
784- double lastInterval = now - selfI.activityState .lastActivity ;
824+ if (selfI.activityState .isGdprForgotten ) {
825+ return ;
826+ }
785827
828+ double lastInterval = now - selfI.activityState .lastActivity ;
786829 selfI.activityState .sessionCount ++;
787830 selfI.activityState .lastInterval = lastInterval;
788-
789831 [selfI transferSessionPackageI: selfI now: now];
790832 [selfI.activityState resetSessionAttributes: now];
791833 [selfI writeActivityStateI: selfI];
@@ -840,6 +882,7 @@ - (void)eventI:(ADJActivityHandler *)selfI
840882 if (![selfI isEnabledI: selfI]) return ;
841883 if (![selfI checkEventI: selfI event: event]) return ;
842884 if (![selfI checkTransactionIdI: selfI transactionId: event.transactionId]) return ;
885+ if (selfI.activityState .isGdprForgotten ) { return ; }
843886
844887 double now = [NSDate .date timeIntervalSince1970 ];
845888
@@ -1044,6 +1087,14 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10441087 return ;
10451088 }
10461089
1090+ // If user is forgotten, forbid re-enabling.
1091+ if (enabled) {
1092+ if ([selfI isGdprForgottenI: selfI]) {
1093+ [selfI.logger debug: @" Re-enabling SDK for forgotten user not allowed" ];
1094+ return ;
1095+ }
1096+ }
1097+
10471098 // save new enabled state in internal state
10481099 selfI.internalState .enabled = enabled;
10491100
@@ -1056,6 +1107,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10561107 return ;
10571108 }
10581109
1110+ // Save new enabled state in activity state.
1111+ selfI.activityState .enabled = enabled;
1112+ [selfI writeActivityStateI: selfI];
1113+
10591114 // Check if upon enabling install has been tracked.
10601115 if (enabled) {
10611116 if (![ADJUserDefaults getInstallTracked ]) {
@@ -1068,12 +1123,12 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled {
10681123 if (deviceToken != nil && ![selfI.activityState.deviceToken isEqualToString: [ADJUtil convertDeviceToken: deviceToken]]) {
10691124 [self setDeviceToken: deviceToken];
10701125 }
1126+
1127+ if ([ADJUserDefaults getGdprForgetMe ]) {
1128+ [selfI setGdprForgetMe ];
1129+ }
10711130 }
10721131
1073- // save new enabled state in activity state
1074- selfI.activityState .enabled = enabled;
1075- [selfI writeActivityStateI: selfI];
1076-
10771132 [selfI checkStatusI: selfI
10781133 pausingState: !enabled
10791134 pausingMessage: @" Pausing handlers due to SDK being disabled"
@@ -1266,6 +1321,9 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI
12661321 if (!selfI.activityState ) {
12671322 return ;
12681323 }
1324+ if (selfI.activityState .isGdprForgotten ) {
1325+ return ;
1326+ }
12691327
12701328 NSString *deviceTokenString = [ADJUtil convertDeviceToken: deviceToken];
12711329
@@ -1303,6 +1361,51 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI
13031361 }
13041362}
13051363
1364+ - (void )setGdprForgetMeI : (ADJActivityHandler *)selfI {
1365+ if (![selfI isEnabledI: selfI]) {
1366+ return ;
1367+ }
1368+ if (!selfI.activityState ) {
1369+ return ;
1370+ }
1371+ if (selfI.activityState .isGdprForgotten == YES ) {
1372+ [ADJUserDefaults removeGdprForgetMe ];
1373+ return ;
1374+ }
1375+
1376+ selfI.activityState .isGdprForgotten = YES ;
1377+ [selfI writeActivityStateI: selfI];
1378+
1379+ // Send GDPR package
1380+ double now = [NSDate .date timeIntervalSince1970 ];
1381+ ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc ] initWithDeviceInfo: selfI.deviceInfo
1382+ activityState: selfI.activityState
1383+ config: selfI.adjustConfig
1384+ sessionParameters: selfI.sessionParameters
1385+ createdAt: now];
1386+
1387+ ADJActivityPackage *gdprPackage = [gdprBuilder buildGdprPackage ];
1388+ [selfI.packageHandler addPackage: gdprPackage];
1389+
1390+ [ADJUserDefaults removeGdprForgetMe ];
1391+
1392+ if (selfI.adjustConfig .eventBufferingEnabled ) {
1393+ [selfI.logger info: @" Buffered gdpr %@ " , gdprPackage.suffix];
1394+ } else {
1395+ [selfI.packageHandler sendFirstPackage ];
1396+ }
1397+ }
1398+
1399+ - (void )setTrackingStateOptedOutI : (ADJActivityHandler *)selfI {
1400+ // In case of web opt out, once response from backend arrives isGdprForgotten field in this moment defaults to NO.
1401+ // Set it to YES regardless of state, since at this moment it should be YES.
1402+ selfI.activityState .isGdprForgotten = YES ;
1403+ [selfI writeActivityStateI: selfI];
1404+
1405+ [selfI setEnabled: NO ];
1406+ [selfI.packageHandler flush ];
1407+ }
1408+
13061409#pragma mark - private
13071410
13081411- (BOOL )isEnabledI : (ADJActivityHandler *)selfI {
@@ -1313,6 +1416,14 @@ - (BOOL)isEnabledI:(ADJActivityHandler *)selfI {
13131416 }
13141417}
13151418
1419+ - (BOOL )isGdprForgottenI : (ADJActivityHandler *)selfI {
1420+ if (selfI.activityState != nil ) {
1421+ return selfI.activityState .isGdprForgotten ;
1422+ } else {
1423+ return NO ;
1424+ }
1425+ }
1426+
13161427- (BOOL )itHasToUpdatePackagesI : (ADJActivityHandler *)selfI {
13171428 if (selfI.activityState != nil ) {
13181429 return selfI.activityState .updatePackages ;
0 commit comments