Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
marandaneto committed Sep 22, 2023
1 parent 3ec8975 commit 58ecd99
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ internal class PostHogSharedPreferences(context: Context, config: PostHogConfig)
private val lock = Any()

override fun getValue(key: String, defaultValue: Any?): Any? {
val defValue: Any?
synchronized(lock) {
return sharedPreferences.all[key] ?: defaultValue
defValue = sharedPreferences.all[key] ?: defaultValue
}
return defValue
}

override fun setValue(key: String, value: Any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import com.posthog.PostHog
import com.posthog.android.sample.ui.theme.PostHogAndroidSampleTheme

class MainActivity : ComponentActivity() {
Expand Down Expand Up @@ -42,7 +43,7 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
// PostHog.identify("my_distinct_id", properties = mapOf("my_property" to 1), userProperties = mapOf("name" to "hello"))
// PostHog.capture("testEvent", mapOf("testProperty" to "testValue"))
// PostHog.reloadFeatureFlagsRequest()
// PostHog.isFeatureEnabled("sessionRecording")
PostHog.isFeatureEnabled("sessionRecording")
// val props = mutableMapOf<String, Any>()
// props["test_key"] = "test_value"
// PostHog.group("theType", "theKey", groupProperties = props)
Expand Down
18 changes: 10 additions & 8 deletions posthog-v3/posthog/api/posthog.api
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ public final class com/posthog/PostHog {
public static final field Companion Lcom/posthog/PostHog$Companion;
public final fun alias (Ljava/lang/String;Ljava/util/Map;)V
public static synthetic fun alias$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V
public final fun capture (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun capture$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun capture (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun capture$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun close ()V
public final fun flush ()V
public final fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public static synthetic fun getFeatureFlag$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
public final fun getFeatureFlagPayload (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public final fun group (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V
public static synthetic fun group$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V
public final fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun identify$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun identify$default (Lcom/posthog/PostHog;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun isFeatureEnabled (Ljava/lang/String;Z)Z
public static synthetic fun isFeatureEnabled$default (Lcom/posthog/PostHog;Ljava/lang/String;ZILjava/lang/Object;)Z
public final fun isOptOut ()Z
public final fun optIn ()V
public final fun optOut ()V
public final fun reloadFeatureFlagsRequest ()V
Expand All @@ -27,8 +28,8 @@ public final class com/posthog/PostHog {
public final class com/posthog/PostHog$Companion {
public final fun alias (Ljava/lang/String;Ljava/util/Map;)V
public static synthetic fun alias$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V
public final fun capture (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun capture$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun capture (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun capture$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun close ()V
public final fun flush ()V
public final fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
Expand All @@ -37,10 +38,11 @@ public final class com/posthog/PostHog$Companion {
public static synthetic fun getFeatureFlagPayload$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
public final fun group (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V
public static synthetic fun group$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V
public final fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun identify$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V
public static synthetic fun identify$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V
public final fun isFeatureEnabled (Ljava/lang/String;Z)Z
public static synthetic fun isFeatureEnabled$default (Lcom/posthog/PostHog$Companion;Ljava/lang/String;ZILjava/lang/Object;)Z
public final fun isOptOut ()Z
public final fun optIn ()V
public final fun optOut ()V
public final fun reloadFeatureFlagsRequest ()V
Expand Down
135 changes: 98 additions & 37 deletions posthog-v3/posthog/src/main/java/com/posthog/PostHog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ public class PostHog private constructor() {
@Volatile
private var enabled = false

private val lock = Any()
private val lockSetup = Any()
private val lockOptOut = Any()
private val anonymousLock = Any()

private var config: PostHogConfig? = null

private var featureFlags: PostHogFeatureFlags? = null
private var api: PostHogApi? = null
private var queue: PostHogQueue? = null
private var memoryPreferences = PostHogMemoryPreferences()

public fun setup(config: PostHogConfig) {
synchronized(lock) {
synchronized(lockSetup) {
try {
if (enabled) {
config.logger.log("Setup called despite already being setup!")
Expand All @@ -36,6 +39,7 @@ public class PostHog private constructor() {
val queue = PostHogQueue(config, api, serializer)
val featureFlags = PostHogFeatureFlags(config, api)

// no need to lock optOut here since the setup is locked already
val optOut = config.cachePreferences?.getValue("opt-out", defaultValue = false) as? Boolean
optOut?.let {
config.optOut = optOut
Expand Down Expand Up @@ -84,8 +88,8 @@ public class PostHog private constructor() {
anonymousId?.let { anon ->
this.anonymousId = anon
}
distinctId?.let { dist ->
this.distinctId = dist
distinctId?.let { distId ->
this.distinctId = distId
}

config.cachePreferences?.remove(config.apiKey)
Expand All @@ -97,7 +101,7 @@ public class PostHog private constructor() {
}

public fun close() {
synchronized(lock) {
synchronized(lockSetup) {
try {
enabled = false

Expand All @@ -118,12 +122,15 @@ public class PostHog private constructor() {

private var anonymousId: String
get() {
var anonymousId = config?.cachePreferences?.getValue("anonymousId") as? String
if (anonymousId == null) {
anonymousId = UUID.randomUUID().toString()
this.anonymousId = anonymousId
var anonymousId: String?
synchronized(anonymousLock) {
anonymousId = config?.cachePreferences?.getValue("anonymousId") as? String
if (anonymousId == null) {
anonymousId = UUID.randomUUID().toString()
this.anonymousId = anonymousId ?: ""
}
}
return anonymousId
return anonymousId ?: ""
}
set(value) {
config?.cachePreferences?.setValue("anonymousId", value)
Expand All @@ -137,7 +144,14 @@ public class PostHog private constructor() {
config?.cachePreferences?.setValue("distinctId", value)
}

private fun buildProperties(distinctId: String, properties: Map<String, Any>?, userProperties: Map<String, Any>?, groupProperties: Map<String, Any>?, appendSharedProps: Boolean = true): Map<String, Any> {
private fun buildProperties(
distinctId: String,
properties: Map<String, Any>?,
userProperties: Map<String, Any>?,
userPropertiesSetOnce: Map<String, Any>?,
groupProperties: Map<String, Any>?,
appendSharedProps: Boolean = true,
): Map<String, Any> {
val props = mutableMapOf<String, Any>()

properties?.let {
Expand Down Expand Up @@ -167,12 +181,15 @@ public class PostHog private constructor() {
}
}

// TODO: $set_once
userProperties?.let {
// TODO: should this be person_properties to decide API?
props["\$set"] = it
}

userPropertiesSetOnce?.let {
props["\$set_once"] = it
}

groupProperties?.let {
props["\$groups"] = it
}
Expand All @@ -186,7 +203,14 @@ public class PostHog private constructor() {
}

// test: $merge_dangerously
public fun capture(event: String, properties: Map<String, Any>? = null, userProperties: Map<String, Any>? = null, groupProperties: Map<String, Any>? = null) {
public fun capture(
event: String,
distinctId: String? = null,
properties: Map<String, Any>? = null,
userProperties: Map<String, Any>? = null,
userPropertiesSetOnce: Map<String, Any>? = null,
groupProperties: Map<String, Any>? = null,
) {
if (!isEnabled()) {
return
}
Expand All @@ -195,7 +219,9 @@ public class PostHog private constructor() {
return
}

val postHogEvent = PostHogEvent(event, distinctId, properties = buildProperties(distinctId, properties, userProperties, groupProperties))
val newDistinctId = distinctId ?: this.distinctId

val postHogEvent = PostHogEvent(event, newDistinctId, properties = buildProperties(newDistinctId, properties, userProperties, userPropertiesSetOnce, groupProperties))
queue?.add(postHogEvent)
}

Expand All @@ -204,17 +230,28 @@ public class PostHog private constructor() {
return
}

config?.optOut = false
config?.cachePreferences?.setValue("opt-out", false)
synchronized(lockOptOut) {
config?.optOut = false
config?.cachePreferences?.setValue("opt-out", false)
}
}

public fun optOut() {
if (!isEnabled()) {
return
}

config?.optOut = true
config?.cachePreferences?.setValue("opt-out", true)
synchronized(lockOptOut) {
config?.optOut = true
config?.cachePreferences?.setValue("opt-out", true)
}
}

public fun isOptOut(): Boolean {
if (!isEnabled()) {
return true
}
return config?.optOut ?: true
}

public fun screen(screenTitle: String, properties: Map<String, Any>? = null) {
Expand Down Expand Up @@ -247,7 +284,12 @@ public class PostHog private constructor() {
capture("\$create_alias", properties = props)
}

public fun identify(distinctId: String, properties: Map<String, Any>? = null, userProperties: Map<String, Any>? = null) {
public fun identify(
distinctId: String,
properties: Map<String, Any>? = null,
userProperties: Map<String, Any>? = null,
userPropertiesSetOnce: Map<String, Any>? = null,
) {
if (!isEnabled()) {
return
}
Expand All @@ -264,7 +306,7 @@ public class PostHog private constructor() {
props.putAll(it)
}

capture("\$identify", properties = props, userProperties = userProperties)
capture("\$identify", properties = props, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce)

if (previousDistinctId != distinctId) {
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
Expand All @@ -287,17 +329,15 @@ public class PostHog private constructor() {
props["\$group_set"] = it
}

config?.memoryPreferences?.let { preferences ->
val groups = preferences.getValue("\$groups") as? Map<String, Any>
val newGroups = mutableMapOf<String, Any>()
groups?.let {
newGroups.putAll(it)
}
newGroups[type] = key
preferences.setValue("\$groups", newGroups)

// TODO: if the group does not exist yet, should we reload the Feature flags?
val groups = memoryPreferences.getValue("\$groups") as? Map<String, Any>
val newGroups = mutableMapOf<String, Any>()
groups?.let {
newGroups.putAll(it)
}
newGroups[type] = key
memoryPreferences.setValue("\$groups", newGroups)

// TODO: if the group does not exist yet, should we reload the Feature flags?

capture("\$groupidentify", properties = props)
}
Expand All @@ -315,9 +355,9 @@ public class PostHog private constructor() {
props["distinct_id"] = distinctId
// TODO: person_properties, group_properties

val groups = config?.memoryPreferences?.getValue("\$groups") as? Map<String, Any>
val groups = memoryPreferences.getValue("\$groups") as? Map<String, Any>

featureFlags?.loadFeatureFlags(buildProperties(distinctId, props, null, groups, appendSharedProps = false))
featureFlags?.loadFeatureFlags(buildProperties(distinctId, props, null, null, groups, appendSharedProps = false))
}

public fun isFeatureEnabled(key: String, defaultValue: Boolean = false): Boolean {
Expand Down Expand Up @@ -361,14 +401,17 @@ public class PostHog private constructor() {
}

public fun reset() {
// TODO: do we need a $device_id? because reset cleans the anon and distinct_id, so technically
// a new user every time, do we wanna know if there are multiple users from the same device?
if (!isEnabled()) {
return
}

memoryPreferences.clear(listOf())
// only remove properties, preserve BUILD and VERSION keys in order to to fix over-sending
// of 'Application Installed' events and under-sending of 'Application Updated' events
config?.cachePreferences?.clear(listOf("build", "build"))
config?.memoryPreferences?.clear(listOf())
featureFlags?.clear()
queue?.clear()
}

Expand Down Expand Up @@ -413,12 +456,24 @@ public class PostHog private constructor() {
shared.close()
}

public fun capture(event: String, properties: Map<String, Any>? = null, userProperties: Map<String, Any>? = null, groupProperties: Map<String, Any>? = null) {
shared.capture(event, properties = properties, userProperties = userProperties, groupProperties = groupProperties)
public fun capture(
event: String,
distinctId: String? = null,
properties: Map<String, Any>? = null,
userProperties: Map<String, Any>? = null,
userPropertiesSetOnce: Map<String, Any>? = null,
groupProperties: Map<String, Any>? = null,
) {
shared.capture(event, distinctId = distinctId, properties = properties, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce, groupProperties = groupProperties)
}

public fun identify(distinctId: String, properties: Map<String, Any>? = null, userProperties: Map<String, Any>? = null) {
shared.identify(distinctId, properties = properties, userProperties = userProperties)
public fun identify(
distinctId: String,
properties: Map<String, Any>? = null,
userProperties: Map<String, Any>? = null,
userPropertiesSetOnce: Map<String, Any>? = null,
) {
shared.identify(distinctId, properties = properties, userProperties = userProperties, userPropertiesSetOnce = userPropertiesSetOnce)
}

public fun reloadFeatureFlagsRequest() {
Expand Down Expand Up @@ -464,5 +519,11 @@ public class PostHog private constructor() {
public fun alias(alias: String, properties: Map<String, Any>? = null) {
shared.alias(alias, properties = properties)
}

public fun isOptOut(): Boolean {
return shared.isOptOut()
}
}
}

// TODO: question about persisted properties, do we cache within the same session?
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.posthog

import com.posthog.internal.PostHogMemoryPreferences
import com.posthog.internal.PostHogNetworkStatus

public class PostHogConfig(
// apiKey and host are immutable due to offline caching
public val apiKey: String,
public val host: String = "https://app.posthog.com",
public var debug: Boolean = false,
@Volatile
public var optOut: Boolean = false,
public var sendFeatureFlagEvent: Boolean = true,
public var preloadFeatureFlags: Boolean = true,
Expand Down Expand Up @@ -46,8 +46,6 @@ public class PostHogConfig(
@PostHogInternal
public var cachePreferences: PostHogPreferences? = null

internal var memoryPreferences: PostHogPreferences = PostHogMemoryPreferences()

@PostHogInternal
public var networkStatus: PostHogNetworkStatus? = null
}
Loading

0 comments on commit 58ecd99

Please sign in to comment.