Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 26.1.2
* Added `CountlyInitProvider` ContentProvider to register activity lifecycle callbacks before `Application.onCreate()`. This ensures the SDK captures the current activity in single-activity frameworks (Flutter, React Native) and apps with deferred initialization.
* Added `CountlyConfig.setInitialActivity(Activity)` as an explicit way for wrapper SDKs to provide the host activity during initialization.
* Added a new config option `setMetricProvider(MetricProvider)` to allow overriding default device metrics with custom values.

## 26.1.1
* Added Content feature method `previewContent(String contentId)` (Experimental!).
Expand Down
136 changes: 136 additions & 0 deletions sdk/src/androidTest/java/ly/count/android/sdk/DeviceInfoTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ of this software and associated documentation files (the "Software"), to deal
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -296,6 +297,141 @@ public void testGetMetricsWithOverride_2() throws UnsupportedEncodingException,
TestUtils.bothJSONObjEqual(json, calculatedJSON);
}

// MetricProvider override tests

@Test
public void testMetricProviderOverride_fullOverride() {
MockedMetricProvider override = new MockedMetricProvider();
DeviceInfo deviceInfo = new DeviceInfo(override);

assertEquals("A", deviceInfo.mp.getOS());
assertEquals("B", deviceInfo.mp.getOSVersion());
assertEquals("C", deviceInfo.mp.getDevice());
assertEquals("D", deviceInfo.mp.getManufacturer());
assertEquals("E", deviceInfo.mp.getResolution(TestUtils.getContext()));
assertEquals("F", deviceInfo.mp.getDensity(TestUtils.getContext()));
assertEquals("G", deviceInfo.mp.getCarrier(TestUtils.getContext()));
assertEquals("66", deviceInfo.mp.getTimezoneOffset());
assertEquals("H", deviceInfo.mp.getLocale());
assertEquals(Countly.DEFAULT_APP_VERSION, deviceInfo.mp.getAppVersion(TestUtils.getContext()));
assertEquals("J", deviceInfo.mp.getStore(TestUtils.getContext()));
assertEquals("K", deviceInfo.mp.getDeviceType(TestUtils.getContext()));
assertEquals("42", deviceInfo.mp.getTotalRAM());
assertEquals("12", deviceInfo.mp.getRamCurrent(TestUtils.getContext()));
assertEquals("48", deviceInfo.mp.getRamTotal());
assertEquals("N", deviceInfo.mp.getCpu());
assertEquals("O", deviceInfo.mp.getOpenGL(TestUtils.getContext()));
assertEquals("6", deviceInfo.mp.getBatteryLevel(TestUtils.getContext()));
assertEquals("S", deviceInfo.mp.getOrientation(TestUtils.getContext()));
assertEquals("T", deviceInfo.mp.isRooted());
assertEquals("U", deviceInfo.mp.isOnline(TestUtils.getContext()));
assertEquals("V", deviceInfo.mp.isMuted(TestUtils.getContext()));
assertEquals("Z", deviceInfo.mp.hasHinge(TestUtils.getContext()));
assertEquals("88", deviceInfo.mp.getRunningTime());

DiskMetric diskMetric = deviceInfo.mp.getDiskSpaces(TestUtils.getContext());
assertEquals("45", diskMetric.totalMb);
assertEquals("23", diskMetric.usedMb);
}

@Test
public void testMetricProviderOverride_partialOverride() {
MetricProvider partial = new MetricProvider() {
@Override public String getOS() { return "CustomOS"; }
@Override public String getDevice() { return "CustomDevice"; }
};
DeviceInfo deviceInfo = new DeviceInfo(partial);

// overridden values
assertEquals("CustomOS", deviceInfo.mp.getOS());
assertEquals("CustomDevice", deviceInfo.mp.getDevice());

// non-overridden values should fall back to SDK defaults
assertEquals(android.os.Build.VERSION.RELEASE, deviceInfo.mp.getOSVersion());
assertEquals(android.os.Build.MODEL, regularDeviceInfo.mp.getDevice());
assertEquals(android.os.Build.MANUFACTURER, deviceInfo.mp.getManufacturer());
assertNotNull(deviceInfo.mp.getLocale());
assertNotNull(deviceInfo.mp.getTimezoneOffset());
assertNotNull(deviceInfo.mp.getAppVersion(TestUtils.getContext()));
}

@Test
public void testMetricProviderOverride_nullOverride() {
DeviceInfo deviceInfo = new DeviceInfo(null);

// all values should be SDK defaults, no crash
assertEquals("Android", deviceInfo.mp.getOS());
assertEquals(android.os.Build.VERSION.RELEASE, deviceInfo.mp.getOSVersion());
assertEquals(android.os.Build.MODEL, deviceInfo.mp.getDevice());
assertEquals(android.os.Build.MANUFACTURER, deviceInfo.mp.getManufacturer());
assertNotNull(deviceInfo.mp.getLocale());
assertNotNull(deviceInfo.mp.getTimezoneOffset());
}

@Test
public void testMetricProviderOverride_emptyOverride() {
MetricProvider emptyOverride = new MetricProvider() {};
DeviceInfo deviceInfo = new DeviceInfo(emptyOverride);

// empty override should behave same as null override
assertEquals("Android", deviceInfo.mp.getOS());
assertEquals(android.os.Build.VERSION.RELEASE, deviceInfo.mp.getOSVersion());
assertEquals(android.os.Build.MODEL, deviceInfo.mp.getDevice());
assertNotNull(deviceInfo.mp.getLocale());
}

@Test
public void testMetricProviderOverride_diskSpacesOverride() {
MetricProvider diskOverride = new MetricProvider() {
@Override public DiskMetric getDiskSpaces(Context context) {
return new DiskMetric("100", "50");
}
};
DeviceInfo deviceInfo = new DeviceInfo(diskOverride);

DiskMetric diskMetric = deviceInfo.mp.getDiskSpaces(TestUtils.getContext());
assertEquals("100", diskMetric.totalMb);
assertEquals("50", diskMetric.usedMb);

// other metrics should be defaults
assertEquals("Android", deviceInfo.mp.getOS());
}

@Test
public void testMetricProviderOverride_timezoneAndRamOverride() {
MetricProvider override = new MetricProvider() {
@Override public String getTimezoneOffset() { return "120"; }
@Override public String getTotalRAM() { return "8192"; }
@Override public String getRamTotal() { return "8192"; }
@Override public String getRamCurrent(Context context) { return "4096"; }
};
DeviceInfo deviceInfo = new DeviceInfo(override);

assertEquals("120", deviceInfo.mp.getTimezoneOffset());
assertEquals("8192", deviceInfo.mp.getTotalRAM());
assertEquals("8192", deviceInfo.mp.getRamTotal());
assertEquals("4096", deviceInfo.mp.getRamCurrent(TestUtils.getContext()));
}

@Test
public void testMetricProviderOverride_metricsJson() throws UnsupportedEncodingException, JSONException {
MetricProvider partial = new MetricProvider() {
@Override public String getOS() { return "CustomOS"; }
@Override public String getDevice() { return "CustomDevice"; }
@Override public String getManufacturer() { return "CustomMfg"; }
};
DeviceInfo deviceInfo = new DeviceInfo(partial);

String calculatedMetrics = URLDecoder.decode(deviceInfo.getMetrics(TestUtils.getContext(), null, new ModuleLog()), "UTF-8");
JSONObject json = new JSONObject(calculatedMetrics);

assertEquals("CustomOS", json.getString("_os"));
assertEquals("CustomDevice", json.getString("_device"));
assertEquals("CustomMfg", json.getString("_manufacturer"));
// non-overridden should still be present with defaults
assertEquals(android.os.Build.VERSION.RELEASE, json.getString("_os_version"));
}

@Test
public void getAppVersionWithOverride() {
Map<String, String> metricOverride = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import android.util.DisplayMetrics;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.AbstractMap;
import java.util.Map;

public class MockedMetricProvider implements MetricProvider {

Expand Down Expand Up @@ -41,8 +39,8 @@ public MockedMetricProvider() {
return "G";
}

@Override public int getTimezoneOffset() {
return 66;
@Override public String getTimezoneOffset() {
return "66";
}

@Override public String getLocale() {
Expand All @@ -61,8 +59,8 @@ public MockedMetricProvider() {
return "K";
}

@Override public long getTotalRAM() {
return 42;
@Override public String getTotalRAM() {
return "42";
}

@Override public String getRamCurrent(Context context) {
Expand Down Expand Up @@ -113,7 +111,7 @@ public MockedMetricProvider() {
return new DisplayMetrics();
}

@Override public Map.Entry<String, String> getDiskSpaces(Context context) {
return new AbstractMap.SimpleEntry<>("45", "23");
@Override public DiskMetric getDiskSpaces(Context context) {
return new DiskMetric("45", "23");
}
}
13 changes: 13 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/CountlyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,19 @@ public synchronized CountlyConfig setLoggingEnabled(boolean enabled) {
return this;
}

/**
* Set a custom metric provider to override default device metrics.
* Only the methods you override will replace the SDK defaults.
* Methods that return null will fall back to the SDK's built-in values.
*
* @param metricProvider Your custom MetricProvider implementation
* @return Returns the same config object for convenient linking
*/
public synchronized CountlyConfig setMetricProvider(MetricProvider metricProvider) {
this.metricProviderOverride = metricProvider;
return this;
}

/**
* Call to enable uncaught crash reporting
*
Expand Down
Loading
Loading