Skip to content

Commit

Permalink
feat: modify session, user engagement preset event, change user scheme (
Browse files Browse the repository at this point in the history
#10)


---------

Co-authored-by: xiaoweii <[email protected]>
  • Loading branch information
zhu-xiaowei and xiaoweii authored May 5, 2023
1 parent 2c9646c commit ebbb399
Show file tree
Hide file tree
Showing 64 changed files with 1,341 additions and 1,186 deletions.
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
7 changes: 5 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand Down Expand Up @@ -47,12 +47,15 @@ ext {
targetSdkVersion = 30
awsSdkVersion = '2.51.0'
amplifySdkVersion = '1.37.2'
lifecycleVersion = "2.6.1"
dependency = [
android: [
desugartools: 'com.android.tools:desugar_jdk_libs:1.0.9',
],
androidx: [
test: 'androidx.test:core:1.5.0'
test: 'androidx.test:core:1.5.0',
lifecycle_common: "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion",
lifecycle_process: "androidx.lifecycle:lifecycle-process:$lifecycleVersion",
],
amplifyframework: [
core: "com.amplifyframework:core:$amplifySdkVersion"
Expand Down
4 changes: 3 additions & 1 deletion clickstream/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,8 @@ dependencies {
implementation dependency.aws.mobileclient
implementation dependency.amplifyframework.core
implementation dependency.okhttp
implementation dependency.androidx.lifecycle_common
implementation dependency.androidx.lifecycle_process

testImplementation dependency.junit
testImplementation dependency.mockito
Expand Down
2 changes: 1 addition & 1 deletion clickstream/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand All @@ -19,6 +19,7 @@
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ProcessLifecycleOwner;

import com.amplifyframework.analytics.AnalyticsEventBehavior;
import com.amplifyframework.analytics.AnalyticsException;
Expand Down Expand Up @@ -60,14 +61,19 @@ public AWSClickstreamPlugin(final Application application) {

@Override
public void identifyUser(@NonNull String userId, @Nullable UserProfile profile) {
analyticsClient.addUserAttribute(Event.ReservedAttribute.USER_ID, userId);
if (profile instanceof ClickstreamUserAttribute) {
for (Map.Entry<String, AnalyticsPropertyBehavior<?>> entry :
((ClickstreamUserAttribute) profile).getUserAttributes()) {
AnalyticsPropertyBehavior<?> property = entry.getValue();
analyticsClient.addUserAttribute(entry.getKey(), property.getValue());
if (userId.equals(Event.ReservedAttribute.USER_ID_UNSET)) {
if (profile instanceof ClickstreamUserAttribute) {
for (Map.Entry<String, AnalyticsPropertyBehavior<?>> entry :
((ClickstreamUserAttribute) profile).getUserAttributes()) {
AnalyticsPropertyBehavior<?> property = entry.getValue();
analyticsClient.addUserAttribute(entry.getKey(), property.getValue());
}
}
} else {
analyticsClient.updateUserId(userId);
}
analyticsClient.updateUserAttribute();
recordEvent(Event.PresetEvent.PROFILE_SET);
}

@Override
Expand All @@ -79,7 +85,7 @@ public void disable() {
@Override
public void enable() {
autoEventSubmitter.start();
activityLifecycleManager.startLifecycleTracking(application);
activityLifecycleManager.startLifecycleTracking(application, ProcessLifecycleOwner.get().getLifecycle());
}

@Override
Expand Down Expand Up @@ -191,7 +197,7 @@ public void configure(
autoEventSubmitter.start();

activityLifecycleManager = new ActivityLifecycleManager(clickstreamManager);
activityLifecycleManager.startLifecycleTracking(application);
activityLifecycleManager.startLifecycleTracking(application, ProcessLifecycleOwner.get().getLifecycle());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand All @@ -21,6 +21,7 @@
public final class AWSClickstreamPluginConfiguration {
private static final long DEFAULT_SEND_EVENTS_INTERVAL = 10000L;
private static final long DEFAULT_CALL_TIME_OUT = 15000L;
private static final long DEFAULT_SESSION_TIME_OUT = 1800000L;

// Clickstream configuration options
private final String appId;
Expand All @@ -30,6 +31,7 @@ public final class AWSClickstreamPluginConfiguration {
private final boolean isTrackAppLifecycleEvents;
private final boolean isTrackAppExceptionEvents;
private final boolean isCompressEvents;
private final long sessionTimeOut;

private AWSClickstreamPluginConfiguration(Builder builder) {
this.appId = builder.appId;
Expand All @@ -39,6 +41,7 @@ private AWSClickstreamPluginConfiguration(Builder builder) {
this.sendEventsInterval = builder.sendEventsInterval;
this.endpoint = builder.endpoint;
this.isCompressEvents = builder.isCompressEvents;
this.sessionTimeOut = builder.sessionTimeOut;
}

/**
Expand Down Expand Up @@ -104,6 +107,15 @@ boolean isCompressEvents() {
return isCompressEvents;
}

/**
* Accessor for session time out.
*
* @return sessionTimeOut
*/
long getSessionTimeOut() {
return sessionTimeOut;
}

/**
* Return a builder that can be used to construct a new instance of
* {@link AWSClickstreamPluginConfiguration}.
Expand All @@ -126,6 +138,8 @@ static final class Builder {
private boolean isTrackAppLifecycleEvents = true;
private boolean isTrackAppExceptionEvents = false;

private long sessionTimeOut = DEFAULT_SESSION_TIME_OUT;

Builder withAppId(final String appId) {
this.appId = appId;
return this;
Expand Down Expand Up @@ -156,6 +170,11 @@ Builder withTrackAppExceptionEvents(final boolean trackAppExceptionEvents) {
return this;
}

Builder withSessionTimeOut(final long sessionTimeOut) {
this.sessionTimeOut = sessionTimeOut;
return this;
}

AWSClickstreamPluginConfiguration build() {
return new AWSClickstreamPluginConfiguration(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,10 @@
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;

import com.amazonaws.logging.Log;
import com.amazonaws.logging.LogFactory;
Expand All @@ -29,7 +33,7 @@
* Tracks when the host application enters or leaves foreground.
* The constructor registers to receive activity lifecycle events.
**/
final class ActivityLifecycleManager implements Application.ActivityLifecycleCallbacks {
final class ActivityLifecycleManager implements Application.ActivityLifecycleCallbacks, LifecycleEventObserver {
private static final Log LOG = LogFactory.getLog(ActivityLifecycleManager.class);

private final SessionClient sessionClient;
Expand All @@ -49,8 +53,9 @@ final class ActivityLifecycleManager implements Application.ActivityLifecycleCal
foregroundActivityCount = 0;
}

void startLifecycleTracking(final Application application) {
void startLifecycleTracking(final Application application, Lifecycle lifecycle) {
application.registerActivityLifecycleCallbacks(this);
lifecycle.addObserver(this);
}

void stopLifecycleTracking(final Application application) {
Expand All @@ -72,7 +77,6 @@ public void onActivityResumed(final Activity activity) {
// An activity came to foreground. Application potentially entered foreground as well
// if there were no other activities in the foreground.
LOG.debug("Activity resumed: " + activity.getLocalClassName());
autoRecordEventClient.recordActivityStart(activity);
checkIfApplicationEnteredForeground();
foregroundActivityCount++;
autoRecordEventClient.recordViewScreen(activity);
Expand All @@ -95,8 +99,6 @@ public void onActivityStopped(final Activity activity) {
LOG.debug("Activity stopped: " + activity.getLocalClassName());
foregroundActivityCount--;
checkIfApplicationEnteredBackground();
autoRecordEventClient.recordUserEngagement(activity);
autoRecordEventClient.removeActivityStart(activity);
}

@Override
Expand All @@ -110,23 +112,6 @@ public void onActivityDestroyed(final Activity activity) {
LOG.debug("Activity destroyed " + activity.getLocalClassName());
}

/**
* Called when the application enters the foreground.
*/
void applicationEnteredForeground() {
LOG.debug("Application entered the foreground.");
sessionClient.startSession();
sessionClient.handleFirstOpen();
}

/**
* Called when the application enters the background.
*/
void applicationEnteredBackground() {
LOG.debug("Application entered the background.");
sessionClient.stopSession();
}

/**
* Called from onActivityResumed to check if the application came to the foreground.
*/
Expand All @@ -135,8 +120,7 @@ private void checkIfApplicationEnteredForeground() {
// indicates we are indeed in the background.
if (foregroundActivityCount == 0 && !inForeground) {
inForeground = true;
// Since this is called when an activity has started, we now know the app has entered the foreground.
applicationEnteredForeground();
LOG.debug("Application open.");
}
}

Expand All @@ -147,7 +131,24 @@ private void checkIfApplicationEnteredBackground() {
// If the App is in the foreground and there are no longer any activities that have not been stopped.
if (foregroundActivityCount == 0 && inForeground) {
inForeground = false;
applicationEnteredBackground();
LOG.debug("Application exit.");
}
}

@Override
public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_STOP) {
LOG.debug("Application entered the background.");
sessionClient.storeSession();
autoRecordEventClient.recordUserEngagement();
} else if (event == Lifecycle.Event.ON_START) {
LOG.debug("Application entered the foreground.");
autoRecordEventClient.updateEngageTimestamp();
autoRecordEventClient.handleFirstOpen();
boolean isNewSession = sessionClient.initialSession();
if (isNewSession) {
autoRecordEventClient.setIsEntrances();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.aws.solution.clickstream;

import androidx.annotation.NonNull;

import com.amplifyframework.analytics.AnalyticsProperties;
import com.amplifyframework.analytics.AnalyticsPropertyBehavior;

import java.util.Objects;

/**
* AnalyticsLongProperty wraps an Long value to store in {@link AnalyticsProperties}.
*/
public final class AnalyticsLongProperty implements AnalyticsPropertyBehavior<Long> {
private final Long value;

private AnalyticsLongProperty(Long value) {
this.value = value;
}

/**
* getValue returns the wrapped Long value stored in the property.
*
* @return The wrapped Boolean value
*/
@NonNull
@Override
public Long getValue() {
return value;
}

/**
* Factory method to instantiate an {@link AnalyticsLongProperty} from a {@link Long} value.
*
* @param value an Long value
* @return an instance of {@link AnalyticsLongProperty}
*/
@NonNull
public static AnalyticsLongProperty from(@NonNull Long value) {
return new AnalyticsLongProperty(Objects.requireNonNull(value));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@

import software.aws.solution.clickstream.client.AnalyticsClient;
import software.aws.solution.clickstream.client.ClickstreamConfiguration;
import software.aws.solution.clickstream.client.Event;

/**
* This is the top-level customer-facing interface to The ClickstreamAnalytics.
Expand Down Expand Up @@ -88,12 +89,12 @@ public static void deleteGlobalAttributes(@NonNull String... attributeName) {
}

/**
* add user.
* add user attributes.
*
* @param userProfile user
*/
public static void addUserAttributes(ClickstreamUserAttribute userProfile) {
Amplify.Analytics.identifyUser(userProfile.getUserId(), userProfile);
Amplify.Analytics.identifyUser(Event.ReservedAttribute.USER_ID_UNSET, userProfile);
}

/**
Expand All @@ -102,7 +103,11 @@ public static void addUserAttributes(ClickstreamUserAttribute userProfile) {
* @param userId user
*/
public static void setUserId(String userId) {
Amplify.Analytics.identifyUser(userId, new ClickstreamUserAttribute.Builder().build());
String newUserId = userId;
if (newUserId == null) {
newUserId = "";
}
Amplify.Analytics.identifyUser(newUserId, new ClickstreamUserAttribute.Builder().build());
}

/**
Expand Down
Loading

0 comments on commit ebbb399

Please sign in to comment.