Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)

App.o2mc.track("MainActivityCreated") // access o2mc by property syntax
App.o2mc.setSessionIdentifier()
App.o2mc.forgetByIdentifier(App.o2mc.sessionIdentifier)
}

/**
Expand All @@ -32,6 +34,7 @@ class MainActivity : AppCompatActivity() {
val text: String = editText.text.toString() // access text by property syntax

App.o2mc.setEndpoint(text)
App.o2mc.forgetByIdentifier(App.o2mc.sessionIdentifier)
}

/**
Expand Down
1 change: 1 addition & 0 deletions android/appkotlin/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,4 @@

</LinearLayout>
</ScrollView>

17 changes: 17 additions & 0 deletions android/sdk/src/main/java/io/o2mc/sdk/O2MC.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,23 @@ public void setSessionIdentifier() {
trackingManager.setSessionIdentifier();
}

/**
* Gets the current user's session identifier.
*/
public String getSessionIdentifier() {
return trackingManager.getSessionIdentifier();
}

/**
* Removes all (personal) data related to the user with given identifier.
* This is in compliance with the 'Right to be forgotten' GDPR laws.
*
* @param identifier the identifier of the user who will be forgotten
*/
public void forgetByIdentifier(String identifier) {
trackingManager.forget(identifier);
}

/**
* Enable or disable logging.
* Logging in release builds is disabled. This behavior is immutable.
Expand Down
21 changes: 21 additions & 0 deletions android/sdk/src/main/java/io/o2mc/sdk/TrackingManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import io.o2mc.sdk.business.DeviceManager;
import io.o2mc.sdk.business.batch.BatchManager;
import io.o2mc.sdk.business.event.EventManager;
import io.o2mc.sdk.business.operations.OperationManager;
import io.o2mc.sdk.domain.DeviceInformation;
import io.o2mc.sdk.domain.Event;
import io.o2mc.sdk.domain.Operation;
import io.o2mc.sdk.exceptions.O2MCDeviceException;
import io.o2mc.sdk.exceptions.O2MCDispatchException;
import io.o2mc.sdk.exceptions.O2MCEndpointException;
Expand Down Expand Up @@ -36,6 +38,7 @@ public class TrackingManager implements O2MCExceptionNotifier {

private DeviceManager deviceManager;
private EventManager eventManager;
private OperationManager operationManager;
private BatchManager batchManager;

private DeviceInformation deviceInformation;
Expand All @@ -48,10 +51,12 @@ public void init(Application application, String endpoint, int dispatchInterval,

this.deviceManager = new DeviceManager();
this.eventManager = new EventManager();
this.operationManager = new OperationManager();
this.batchManager = new BatchManager();

this.deviceManager.init(this, application);
this.eventManager.init(this);
this.operationManager.init(this);
this.batchManager.init(this, endpoint, dispatchInterval, maxRetries);
}

Expand All @@ -71,6 +76,10 @@ public void track(String eventName) {
eventManager.newEvent(eventName);
}

public void forget(String identifier) {
operationManager.newOperationWithProperties(Operation.FORGET_BY_ID, identifier);
}

public void trackWithProperties(String eventName, Object value) {
eventManager.newEventWithProperties(eventName, value);
}
Expand All @@ -79,10 +88,18 @@ public List<Event> getEventsFromBus() {
return eventManager.getEvents();
}

public List<Operation> getOperationsFromBus() {
return operationManager.getOperations();
}

public void clearEventsFromBus() {
eventManager.reset();
}

public void clearOperationsFromBus() {
operationManager.reset();
}

/**
* Return device information. Generate if it hasn't been generated before.
*
Expand Down Expand Up @@ -125,6 +142,10 @@ public void setSessionIdentifier() {
batchManager.setIdentifier(Util.generateUUID());
}

public String getSessionIdentifier() {
return batchManager.getIdentifier();
}

@Override public void notifyException(O2MCException e, boolean isFatal) {
if (o2MCExceptionListener != null) { // if listener is set, inform using an exception

Expand Down
55 changes: 51 additions & 4 deletions android/sdk/src/main/java/io/o2mc/sdk/business/batch/BatchBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import io.o2mc.sdk.domain.Batch;
import io.o2mc.sdk.domain.DeviceInformation;
import io.o2mc.sdk.domain.Event;
import io.o2mc.sdk.domain.Operation;
import io.o2mc.sdk.exceptions.O2MCInternalException;
import io.o2mc.sdk.interfaces.O2MCExceptionNotifier;
import io.o2mc.sdk.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -26,7 +29,10 @@ public class BatchBus {
private boolean awaitingCallback;
private Batch pendingBatch;

BatchBus() {
private O2MCExceptionNotifier o2mcExceptionNotifier;

BatchBus(O2MCExceptionNotifier o2mcExceptionNotifier) {
this.o2mcExceptionNotifier = o2mcExceptionNotifier;
this.batches = new ArrayList<>();
}

Expand All @@ -41,11 +47,47 @@ public void setDeviceInformation(DeviceInformation deviceInformation) {
}
}

public Batch generateBatch(String batchId, List<Event> events) {
public Batch generateBatch(String batchId, List<Event> events, List<Operation> operations) {
// Events may be null/empty
// Operations may be null/empty
// But at least one of those lists must be non-empty

// Make sure we have a valid list of events
List<Event> eventsLocal;
if (events == null) {
eventsLocal = new ArrayList<>();
} else if (events.size() == 0) {
eventsLocal = new ArrayList<>();
} else { // We have at least one event, use it
eventsLocal = new ArrayList<>(events);
}

// Make sure we have a valid list of operations
List<Operation> operationsLocal;
if (operations == null) {
operationsLocal = new ArrayList<>();
} else if (operations.size() == 0) {
operationsLocal = new ArrayList<>();
} else { // We have at least one operation, use it
operationsLocal = new ArrayList<>(operations);
}

if (eventsLocal.size() == 0 && operationsLocal.size() == 0) {
// If we have neither any events nor operations, we shouldn't even be creating this batch
// Something went wrong earlier, notify developer
o2mcExceptionNotifier.notifyException(
new O2MCInternalException(
"There are no events nor operations while generating a batch. We should not be generating a batch without either of those. Find out how we got to this point and prevent it from happening again."),
false
// Not fatal, just unusual behavior which should be looked into before it causes any trouble in the future
);
}

return new Batch(
deviceInformation,
TimeUtil.generateTimestamp(),
new ArrayList<>(events), // generate a new list, don't use a reference to the list
eventsLocal,
operationsLocal,
batchCounter++, /*add 1 to the counter after this statement*/
batchId,
0
Expand Down Expand Up @@ -140,10 +182,15 @@ private Batch mergeBatches(List<Batch> batches) {
allEvents.addAll(b.getEvents());
}

List<Operation> allOperations = new ArrayList<>();
for (Batch b : batches) {
allOperations.addAll(b.getOperations());
}

// The batch ID is the same for every batch in the current user session, doesn't matter if we get the 1st one or the last one
String batchId = batches.get(0).getSessionId();

return generateBatch(batchId, allEvents);
return generateBatch(batchId, allEvents, allOperations);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.o2mc.sdk.Config;
import io.o2mc.sdk.TrackingManager;
import io.o2mc.sdk.domain.Event;
import io.o2mc.sdk.domain.Operation;
import io.o2mc.sdk.exceptions.O2MCDispatchException;
import io.o2mc.sdk.exceptions.O2MCEndpointException;
import io.o2mc.sdk.util.Util;
Expand Down Expand Up @@ -51,7 +52,7 @@ public class BatchManager extends TimerTask implements Callback {
*/
public void init(TrackingManager trackingManager, String endpoint, int dispatchInterval,
int maxRetries) {
batchBus = new BatchBus();
batchBus = new BatchBus(trackingManager);
batchDispatcher = new BatchDispatcher(this);

this.trackingManager = trackingManager;
Expand All @@ -65,6 +66,10 @@ public void setIdentifier(String identifier) {
this.batchId = identifier;
}

public String getIdentifier() {
return batchId;
}

/**
* Sets the max amount of retries for generating batches. Helps to reduce cpu usage / battery draining.
*
Expand Down Expand Up @@ -149,13 +154,24 @@ private List<Event> getEvents() {
return trackingManager.getEventsFromBus();
}

private List<Operation> getOperations() {
return trackingManager.getOperationsFromBus();
}

/**
* Clears all events which are currently in the EventBus.
*/
private void clearEvents() {
trackingManager.clearEventsFromBus();
}

/**
* Clears all operations which are currently in the OperationBus.
*/
private void clearOperations() {
trackingManager.clearOperationsFromBus();
}

public void reset() {
batchBus.clearBatches();
batchBus.clearPending();
Expand Down Expand Up @@ -234,11 +250,12 @@ public void run() {
}

// Only generate a batch if we have events
if (getEvents().size() > 0) {
batchBus.add(batchBus.generateBatch(batchId, getEvents()));
if (getEvents().size() > 0 || getOperations().size() > 0) {
batchBus.add(batchBus.generateBatch(batchId, getEvents(), getOperations()));
LogD(TAG,
String.format("run: Newly generated batch contains '%s' events", getEvents().size()));
clearEvents();
clearOperations();
}

// If there's a batch pending, skip this run
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
import java.util.List;

/**
* Manages everything that's related to events by making use of a EventBus.
* Manages everything that's related to events by making use of an EventBus.
*/
public class EventManager {

private EventBus eventBus;
private boolean isStopped;

// Will be used for future exception handling, once this class gets more complex
@SuppressWarnings({ "FieldCanBeLocal", "unused" }) private O2MCExceptionNotifier notifier;
private O2MCExceptionNotifier notifier;

public void init(O2MCExceptionNotifier notifier) {
this.eventBus = new EventBus();
Expand Down Expand Up @@ -59,7 +58,7 @@ public void newEventWithProperties(String eventName, Object value) {

if (!Util.isValidEventValue(value)) {
notifier.notifyException(
new O2MCTrackException(String.format("Value '%s' is invalid.", value)),
new O2MCTrackException(String.format("Event value '%s' is invalid.", value)),
false); // is not fatal for base SDK functionality, next event value may be valid again
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.o2mc.sdk.business.operations;

import io.o2mc.sdk.domain.Operation;
import io.o2mc.sdk.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;

/**
* Holds all operations generated by user interaction from the app implementing our SDK.
*/
public class OperationBus {

private final List<Operation> operations;

public OperationBus() {
operations = new ArrayList<>();
}

public void add(Operation o) {
operations.add(o);
}

public void clearOperations() {
operations.clear();
}

public List<Operation> getOperations() {
return operations;
}

public Operation generateOperation(int operationCode) {
return new Operation(operationCode, null, TimeUtil.generateTimestamp());
}

public Operation generateOperationWithProperties(int operationCode, Object properties) {
return new Operation(operationCode, properties, TimeUtil.generateTimestamp());
}
}
Loading