Skip to content

Commit

Permalink
feat(libraries): add groups, multivar FF, continuity support for post…
Browse files Browse the repository at this point in the history
…hog-android (PostHog#11)

Co-authored-by: Li Yi Yu <[email protected]>
  • Loading branch information
alexkim205 and liyiy authored Jul 22, 2022
1 parent 15bcec6 commit 7107ec0
Show file tree
Hide file tree
Showing 27 changed files with 1,169 additions and 75 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,6 @@ build/

# Ignore Gradle GUI config
gradle-app.setting

# Jacoco
/posthog/jacoco.exec
5 changes: 5 additions & 0 deletions posthog-samples/posthog-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ android {
disable 'IconMissingDensityFolder', 'GoogleAppIndexingWarning', 'AllowBackup'
}

compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}

defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

import com.posthog.android.Options;
import com.posthog.android.PostHog;
import com.posthog.android.Properties;

import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;

public class MainActivity extends Activity {
Expand Down Expand Up @@ -70,6 +73,25 @@ void onButtonBClicked() {
PostHog.with(this).capture("Button B Clicked");
}

@OnClick(R.id.action_is_feature_enabled)
void onIsFeatureEnabledClick() {
if (PostHog.with(this).isFeatureEnabled("enabled-flag")) {
PostHog.with(this).capture("isFeatureEnabled test", null, new Options().putContext("send_feature_flags", true));
}
}

@OnClick(R.id.action_get_feature_flag)
void onGetFeatureFlagClick() {
if ((Boolean) PostHog.with(this).getFeatureFlag("enabled-flag")) {
PostHog.with(this).capture("getFeatureFlag test", null, new Options().putContext("send_feature_flags", true));
}
}

@OnClick(R.id.action_group_identify)
void onGroupIdentify() {
PostHog.with(this).group("group-type", "group-key");
}

@OnClick(R.id.action_identify)
void onIdentifyButtonClicked() {
String id = distinctId.getText().toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
package com.posthog.android.sample;

import android.app.Application;
import android.util.Log;
import com.posthog.android.PostHog;
import com.posthog.android.Properties;

import uk.co.chrisjenx.calligraphy.CalligraphyConfig;

public class SampleApp extends Application {

private static final String POSTHOG_API_KEY = "8jVz0YZ2YPtP7eL1I5l5RQIp-WcuFeD3pZO8c0YDMx4";
private static final String POSTHOG_API_KEY = "phc_X8B6bhR1QgQKP1WdpFLN82LxLxgZ7WPXDgJyRyvIpib";

@Override
public void onCreate() {
Expand All @@ -46,7 +47,7 @@ public void onCreate() {

// Initialize a new instance of the PostHog client.
PostHog.Builder builder =
new PostHog.Builder(this, POSTHOG_API_KEY, "http://d37f3802.ngrok.io")
new PostHog.Builder(this, POSTHOG_API_KEY, "https://app.posthog.com")
.captureApplicationLifecycleEvents()
.recordScreenViews();

Expand All @@ -55,5 +56,8 @@ public void onCreate() {

// Now anytime you call PostHog.with, the custom instance will be returned.
PostHog posthog = PostHog.with(this);

// Identify from the getgo
PostHog.with(this).identify("test_distinct_id", new Properties().putValue("name", "my name").putValue("email", "[email protected]"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/action_is_feature_enabled"
android:text="@string/button_is_feature_enabled"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/action_get_feature_flag"
android:text="@string/button_get_feature_flag"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/action_group_identify"
android:text="@string/button_group_identify"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<View
android:background="@android:color/black"
android:layout_width="match_parent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@

<string name="button_a">Button A</string>
<string name="button_b">Button B</string>
<string name="button_is_feature_enabled">Is Feature Enabled</string>
<string name="button_get_feature_flag">Get Feature Flag</string>
<string name="button_group_identify">Identify group</string>

<string name="flush">Flush Events</string>

Expand Down
5 changes: 5 additions & 0 deletions posthog-samples/posthog-wear-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ android {
minSdkVersion rootProject.ext.minSdkVersionWear
}

compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}

lintOptions {
// Since this is just a sample app, it's ok to ignore these warnings.
disable 'IconMissingDensityFolder', 'GoogleAppIndexingWarning', 'AllowBackup'
Expand Down
39 changes: 24 additions & 15 deletions posthog/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,32 @@ apply plugin: 'com.getkeepsafe.dexcount'
apply from: rootProject.file('gradle/android.gradle')

dependencies {
api rootProject.ext.deps.supportAnnotations
api rootProject.ext.deps.supportAnnotations
implementation 'com.google.code.gson:gson:2.9.0'

testImplementation 'junit:junit:4.13'
testImplementation('org.robolectric:robolectric:3.5') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
testImplementation 'com.squareup.assertj:assertj-android:1.2.0'
testImplementation 'org.mockito:mockito-core:1.10.19'
testImplementation 'com.squareup.okio:okio:1.14.0'
testImplementation 'com.squareup.okhttp:mockwebserver:2.7.5'
testImplementation 'com.squareup.burst:burst-junit4:1.2.0'
testImplementation 'junit:junit:4.13'
testImplementation('org.robolectric:robolectric:3.5') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
testImplementation 'com.squareup.assertj:assertj-android:1.2.0'
testImplementation 'org.mockito:mockito-core:1.10.19'
testImplementation 'com.squareup.okio:okio:1.14.0'
testImplementation 'com.squareup.okhttp:mockwebserver:2.7.5'
testImplementation 'com.squareup.burst:burst-junit4:1.2.0'

// We're intentionally on assertj 1.7.1 as the latest (3.8.0 as of 22/12/2017) is not compatible
// with Android.
//noinspection GradleDependency
testImplementation 'org.assertj:assertj-core:1.7.1'
// We're intentionally on assertj 1.7.1 as the latest (3.8.0 as of 22/12/2017) is not compatible
// with Android.
//noinspection GradleDependency
testImplementation 'org.assertj:assertj-core:1.7.1'
testImplementation project(path: ':posthog')
}

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

apply from: rootProject.file('gradle/attach-jar.gradle')
Expand Down
5 changes: 5 additions & 0 deletions posthog/src/main/java/com/posthog/android/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ Connection batch() throws IOException {
return createPostConnection(connection);
}

Connection decide() throws IOException {
HttpURLConnection connection = connectionFactory.decide(this.host);
return createPostConnection(connection);
}

/** Represents an HTTP exception thrown for unexpected/non 2xx response codes. */
static class HTTPException extends IOException {
final int responseCode;
Expand Down
15 changes: 13 additions & 2 deletions posthog/src/main/java/com/posthog/android/ConnectionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
*/
package com.posthog.android;

import android.util.Base64;
import com.posthog.core.BuildConfig;
import java.io.IOException;
import java.net.HttpURLConnection;
Expand Down Expand Up @@ -54,7 +53,19 @@ public HttpURLConnection batch(String host) throws IOException {
}

/**
* Configures defaults for connections opened with {@link #batch(String)}.
* Return a {@link HttpURLConnection} that makes decide requests to {@code
* https://app.posthog.com/decide/?v=2}.
*/
public HttpURLConnection decide(String host) throws IOException {
HttpURLConnection connection = openConnection(host + "/decide/?v=2");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
return connection;
}

/**
* Configures defaults for connections opened.
*/
protected HttpURLConnection openConnection(String url) throws IOException {
URL requestedURL;
Expand Down
4 changes: 4 additions & 0 deletions posthog/src/main/java/com/posthog/android/Integration.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import android.support.annotation.NonNull;
import com.posthog.android.payloads.AliasPayload;
import com.posthog.android.payloads.CapturePayload;
import com.posthog.android.payloads.GroupPayload;
import com.posthog.android.payloads.IdentifyPayload;
import com.posthog.android.payloads.ScreenPayload;

Expand Down Expand Up @@ -87,6 +88,9 @@ public void capture(CapturePayload capture) {}
/** @see PostHog#alias(String, com.posthog.android.Options) */
public void alias(AliasPayload alias) {}

/** @see PostHog#group(String, String, com.posthog.android.Properties) */
public void group(GroupPayload group) {}

/**
* @see PostHog#screen(String, com.posthog.android.Properties,
* com.posthog.android.Options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.app.Activity;
import android.os.Bundle;
import com.posthog.android.payloads.AliasPayload;
import com.posthog.android.payloads.GroupPayload;
import com.posthog.android.payloads.IdentifyPayload;
import com.posthog.android.payloads.ScreenPayload;
import com.posthog.android.payloads.CapturePayload;
Expand Down Expand Up @@ -190,6 +191,20 @@ public String toString() {
};
}

static IntegrationOperation group(final GroupPayload groupPayload) {
return new IntegrationOperation() {
@Override
void run(Integration<?> integration) {
integration.group(groupPayload);
}

@Override
public String toString() {
return groupPayload.toString();
}
};
}

static final IntegrationOperation FLUSH =
new IntegrationOperation() {
@Override
Expand Down
76 changes: 76 additions & 0 deletions posthog/src/main/java/com/posthog/android/Persistence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.posthog.android;

import static java.util.Collections.unmodifiableMap;

import android.content.Context;

import com.posthog.android.internal.Utils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Persistence layer is a cache map attached to a PostHog singleton instance
*/
public class Persistence extends ValueMap {
public static final String ENABLED_FEATURE_FLAGS_KEY = "$enabled_feature_flags";
public static final String GROUPS_KEY = "$groups";

static Persistence create() {
Persistence persistence = new Persistence();
return persistence;
}

public Persistence() {}

public Persistence(int initialCapacity) {
super(initialCapacity);
}

// For deserialization
Persistence(Map<String, Object> delegate) {
super(delegate);
}

public Persistence unmodifiableCopy() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>(this);
return new Persistence(unmodifiableMap(map));
}

Persistence putEnabledFeatureFlags(Map featureFlags) {
return putValue(ENABLED_FEATURE_FLAGS_KEY, featureFlags);
}

public ValueMap enabledFeatureFlags() {
return getValueMap(ENABLED_FEATURE_FLAGS_KEY);
}

Persistence putGroups(Map groups) {
return putValue(GROUPS_KEY, groups);
}

public ValueMap groups() {
return getValueMap(GROUPS_KEY);
}

@Override
public Persistence putValue(String key, Object value) {
super.putValue(key, value);
return this;
}

static class Cache extends ValueMap.Cache<Persistence> {

Cache(Context context, Cartographer cartographer, String tag) {
super(context, cartographer, tag, tag, Persistence.class);
}

@Override
public Persistence create(Map<String, Object> map) {
// PostHog client can be called on any thread, so this instance should be thread safe.
return new Persistence(new Utils.NullableConcurrentHashMap<>(map));
}
}

}
Loading

0 comments on commit 7107ec0

Please sign in to comment.