Skip to content

Commit

Permalink
Handle being able to be minified by ProGuard (#43)
Browse files Browse the repository at this point in the history
* tests passing

* clean up serialization code

* consistent ordering for getters and setters

* changes from self-review of PR

* pass in API key using root-level local.properties

* feedback from PR

* cache images also based on gradle settings
  • Loading branch information
aarsilv committed Apr 9, 2024
1 parent c04fe9c commit 34c5c51
Show file tree
Hide file tree
Showing 18 changed files with 439 additions and 69 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Expand Up @@ -65,7 +65,7 @@ jobs:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-33
key: avd-api-33-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}

- name: create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
Expand Down
Expand Up @@ -48,7 +48,7 @@

import cloud.eppo.android.dto.EppoValue;
import cloud.eppo.android.dto.SubjectAttributes;
import cloud.eppo.android.dto.adapters.EppoValueAdapter;
import cloud.eppo.android.dto.deserializers.EppoValueAdapter;

public class EppoClientTest {
private static final String TAG = logTag(EppoClient.class);
Expand Down
7 changes: 7 additions & 0 deletions eppo/src/main/java/cloud/eppo/android/CacheLoadCallback.java
@@ -0,0 +1,7 @@
package cloud.eppo.android;

public interface CacheLoadCallback {
void onCacheLoadSuccess();

void onCacheLoadFail();
}
23 changes: 18 additions & 5 deletions eppo/src/main/java/cloud/eppo/android/ConfigurationRequestor.java
Expand Up @@ -8,6 +8,7 @@
import com.google.gson.JsonSyntaxException;

import java.io.Reader;
import java.util.concurrent.atomic.AtomicBoolean;

import cloud.eppo.android.dto.FlagConfig;

Expand All @@ -23,7 +24,19 @@ public ConfigurationRequestor(ConfigurationStore configurationStore, EppoHttpCli
}

public void load(InitializationCallback callback) {
boolean usedCache = configurationStore.loadFromCache(callback);
AtomicBoolean cachedUsed = new AtomicBoolean(false);
configurationStore.loadFromCache(new CacheLoadCallback() {
@Override
public void onCacheLoadSuccess() {
cachedUsed.set(true);
callback.onCompleted();
}

@Override
public void onCacheLoadFail() {
cachedUsed.set(false);
}
});

client.get("/api/randomized_assignment/v3/config", new RequestCallback() {
@Override
Expand All @@ -32,21 +45,21 @@ public void onSuccess(Reader response) {
configurationStore.setFlags(response);
} catch (JsonSyntaxException | JsonIOException e) {
Log.e(TAG, "Error loading configuration response", e);
if (callback != null && !usedCache) {
callback.onError("Unable to load configuration");
if (callback != null && !cachedUsed.get()) {
callback.onError("Unable to request configuration");
}
return;
}

if (callback != null && !usedCache) {
if (callback != null && !cachedUsed.get()) {
callback.onCompleted();
}
}

@Override
public void onFailure(String errorMessage) {
Log.e(TAG, errorMessage);
if (callback != null && !usedCache) {
if (callback != null && !cachedUsed.get()) {
callback.onError(errorMessage);
}
}
Expand Down
26 changes: 11 additions & 15 deletions eppo/src/main/java/cloud/eppo/android/ConfigurationStore.java
Expand Up @@ -21,14 +21,16 @@
import cloud.eppo.android.dto.EppoValue;
import cloud.eppo.android.dto.FlagConfig;
import cloud.eppo.android.dto.RandomizationConfigResponse;
import cloud.eppo.android.dto.adapters.EppoValueAdapter;
import cloud.eppo.android.dto.deserializers.EppoValueAdapter;
import cloud.eppo.android.dto.deserializers.RandomizationConfigResponseDeserializer;
import cloud.eppo.android.util.Utils;

public class ConfigurationStore {

private static final String TAG = logTag(ConfigurationStore.class);

private final Gson gson = new GsonBuilder()
.registerTypeAdapter(RandomizationConfigResponse.class, new RandomizationConfigResponseDeserializer())
.registerTypeAdapter(EppoValue.class, new EppoValueAdapter())
.serializeNulls()
.create();
Expand All @@ -43,10 +45,11 @@ public ConfigurationStore(Application application) {
this.sharedPrefs = Utils.getSharedPrefs(application);
}

public boolean loadFromCache(InitializationCallback callback) {
public void loadFromCache(CacheLoadCallback callback) {
if (flags != null || !cacheFile.exists()) {
Log.d(TAG, "Not loading from cache ("+(flags == null ? "null flags" : "non-null flags")+")");
return false;
callback.onCacheLoadFail();
return;
}

AsyncTask.execute(() -> {
Expand All @@ -57,35 +60,28 @@ public boolean loadFromCache(InitializationCallback callback) {
RandomizationConfigResponse configResponse = gson.fromJson(reader, RandomizationConfigResponse.class);
reader.close();
if (configResponse == null || configResponse.getFlags() == null) {
// Invalid cached configuration, initialize as an empty map and delete file
throw new JsonSyntaxException("Configuration file missing flags");
}
flags = configResponse.getFlags();
updateConfigsInSharedPrefs();
}
Log.d(TAG, "Cache loaded successfully");
callback.onCacheLoadSuccess();
} catch (Exception e) {
Log.e(TAG, "Error loading from local cache", e);
cacheFile.delete();

if (callback != null) {
callback.onError("Unable to load config from cache");
}
}

if (callback != null) {
callback.onCompleted();
callback.onCacheLoadFail();
}
});
return true;
}

public void setFlags(Reader response) {
RandomizationConfigResponse config = gson.fromJson(response, RandomizationConfigResponse.class);
flags = config.getFlags();
if (flags == null) {
if (config == null || config.getFlags() == null) {
Log.w(TAG, "Flags missing in configuration response");
flags = new ConcurrentHashMap<>();
} else {
flags = config.getFlags();
}

// update any existing flags already in shared prefs
Expand Down
11 changes: 8 additions & 3 deletions eppo/src/main/java/cloud/eppo/android/dto/Allocation.java
@@ -1,20 +1,25 @@
package cloud.eppo.android.dto;

import java.util.List;
import com.google.gson.annotations.SerializedName;

public class Allocation {
@SerializedName("percentExposure")
private float percentExposure;

@SerializedName("variations")
private List<Variation> variations;

public float getPercentExposure() {
return percentExposure;
}

public void setPercentExposure(float percentExposure) {
this.percentExposure = percentExposure;
}

public List<Variation> getVariations() {
return variations;
}

public void setVariations(List<Variation> variations) {
this.variations = variations;
}
}
27 changes: 20 additions & 7 deletions eppo/src/main/java/cloud/eppo/android/dto/FlagConfig.java
@@ -1,44 +1,57 @@
package cloud.eppo.android.dto;

import com.google.gson.annotations.SerializedName;

import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class FlagConfig {
@SerializedName("subjectShards")
private int subjectShards;

@SerializedName("enabled")
private boolean enabled;

@SerializedName("typedOverrides")
private Map<String, String> typedOverrides = new HashMap<>();

@SerializedName("rules")
private List<TargetingRule> rules;

@SerializedName("allocations")
private Map<String, Allocation> allocations;

public int getSubjectShards() {
return subjectShards;
}

public void setSubjectShards(int subjectShards) {
this.subjectShards = subjectShards;
}

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public Map<String, String> getTypedOverrides() {
return typedOverrides;
}

public void setTypedOverrides(Map<String, String> typedOverrides) {
this.typedOverrides = typedOverrides;
}

public Map<String, Allocation> getAllocations() {
return allocations;
}

public void setAllocations(Map<String, Allocation> allocations) {
this.allocations = allocations;
}

public List<TargetingRule> getRules() {
return rules;
}

public void setRules(List<TargetingRule> rules) {
this.rules = rules;
}
}
@@ -1,13 +1,15 @@
package cloud.eppo.android.dto;

import java.util.concurrent.ConcurrentHashMap;
import com.google.gson.annotations.SerializedName;

public class RandomizationConfigResponse {
@SerializedName("flags")
private ConcurrentHashMap<String, FlagConfig> flags;

public ConcurrentHashMap<String, FlagConfig> getFlags() {
return flags;
}

public void setFlags(ConcurrentHashMap<String, FlagConfig> flags) {
this.flags = flags;
}
}
12 changes: 4 additions & 8 deletions eppo/src/main/java/cloud/eppo/android/dto/ShardRange.java
@@ -1,25 +1,21 @@
package cloud.eppo.android.dto;

import com.google.gson.annotations.SerializedName;

public class ShardRange {
@SerializedName("start")
private int start;
@SerializedName("end")
private int end;

public int getStart() {
return start;
}

public int getEnd() {
return end;
}

public void setStart(int start) {
this.start = start;
}

public int getEnd() {
return end;
}

public void setEnd(int end) {
this.end = end;
}
Expand Down
21 changes: 8 additions & 13 deletions eppo/src/main/java/cloud/eppo/android/dto/TargetingCondition.java
@@ -1,37 +1,32 @@
package cloud.eppo.android.dto;

import com.google.gson.annotations.SerializedName;

public class TargetingCondition {
@SerializedName("operator")
private String operator;

@SerializedName("attribute")
private String attribute;

@SerializedName("value")
private EppoValue value;

public OperatorType getOperator() {
return OperatorType.fromString(operator);
}

public String getAttribute() {
return attribute;
}

public EppoValue getValue() {
return value;
}

public void setOperator(OperatorType operatorType) {
this.operator = operatorType.value;
}

public String getAttribute() {
return attribute;
}

public void setAttribute(String attribute) {
this.attribute = attribute;
}

public EppoValue getValue() {
return value;
}

public void setValue(EppoValue value) {
this.value = value;
}
Expand Down
8 changes: 5 additions & 3 deletions eppo/src/main/java/cloud/eppo/android/dto/TargetingRule.java
@@ -1,18 +1,20 @@
package cloud.eppo.android.dto;

import java.util.List;
import com.google.gson.annotations.SerializedName;

public class TargetingRule {
@SerializedName("allocationKey")
private String allocationKey;

@SerializedName("conditions")
private List<TargetingCondition> conditions;

public String getAllocationKey() {
return allocationKey;
}

public void setAllocationKey(String allocationKey) {
this.allocationKey = allocationKey;
}

public List<TargetingCondition> getConditions() {
return conditions;
}
Expand Down
14 changes: 9 additions & 5 deletions eppo/src/main/java/cloud/eppo/android/dto/Variation.java
@@ -1,19 +1,23 @@
package cloud.eppo.android.dto;

import com.google.gson.annotations.SerializedName;

public class Variation {
@SerializedName("typedValue")
private EppoValue typedValue;

@SerializedName("shardRange")

private ShardRange shardRange;

public EppoValue getTypedValue() {
return typedValue;
}

public void setTypedValue(EppoValue typedValue) {
this.typedValue = typedValue;
}

public ShardRange getShardRange() {
return shardRange;
}

public void setShardRange(ShardRange shardRange) {
this.shardRange = shardRange;
}
}

0 comments on commit 34c5c51

Please sign in to comment.