diff --git a/samples/java_layout/src/main/AndroidManifest.xml b/samples/java_layout/src/main/AndroidManifest.xml
index 55127d4bb..341585076 100644
--- a/samples/java_layout/src/main/AndroidManifest.xml
+++ b/samples/java_layout/src/main/AndroidManifest.xml
@@ -123,6 +123,10 @@
android:name=".ui.common.SimpleFragmentActivity"
android:exported="false"
android:label="@string/label_simple_fragment_activity" />
+
fromMap(@NonNull Map
CustomerIOSDKConfig defaultConfig = getDefaultConfigurations();
String apiHost = bundle.get(Keys.API_HOST);
String cdnHost = bundle.get(Keys.CDN_HOST);
- Integer flushInterval = StringUtils.parseInteger(bundle.get(Keys.FLUSH_INTERVAL), defaultConfig.flushInterval);
- Integer flushAt = StringUtils.parseInteger(bundle.get(Keys.FLUSH_AT), defaultConfig.flushAt);
boolean screenTrackingEnabled = StringUtils.parseBoolean(bundle.get(Keys.TRACK_SCREENS), defaultConfig.screenTrackingEnabled);
boolean deviceAttributesTrackingEnabled = StringUtils.parseBoolean(bundle.get(Keys.TRACK_DEVICE_ATTRIBUTES), defaultConfig.deviceAttributesTrackingEnabled);
- boolean debugModeEnabled = StringUtils.parseBoolean(bundle.get(Keys.DEBUG_MODE), defaultConfig.debugModeEnabled);
+ CioLogLevel logLevel = CioLogLevel.Companion.getLogLevel(bundle.get(Keys.LOG_LEVEL), CioLogLevel.DEBUG);
+ Region region = Region.Companion.getRegion(bundle.get(Keys.REGION), Region.US.INSTANCE);
+ boolean applicationLifecycleTrackingEnabled = StringUtils.parseBoolean(bundle.get(Keys.TRACK_APPLICATION_LIFECYCLE), defaultConfig.applicationLifecycleTrackingEnabled);
+ boolean testModeEnabled = StringUtils.parseBoolean(bundle.get(Keys.TEST_MODE_ENABLED), defaultConfig.testModeEnabled);
+ boolean inAppMessagingEnabled = StringUtils.parseBoolean(bundle.get(Keys.IN_APP_MESSAGING_ENABLED), defaultConfig.inAppMessagingEnabled);
CustomerIOSDKConfig config = new CustomerIOSDKConfig(cdpApiKey,
siteId,
apiHost,
cdnHost,
- flushInterval,
- flushAt,
screenTrackingEnabled,
deviceAttributesTrackingEnabled,
- debugModeEnabled);
+ logLevel,
+ region,
+ applicationLifecycleTrackingEnabled,
+ testModeEnabled,
+ inAppMessagingEnabled);
return Optional.of(config);
}
@@ -78,11 +87,13 @@ public static Map toMap(@NonNull CustomerIOSDKConfig config) {
bundle.put(Keys.SITE_ID, config.siteId);
bundle.put(Keys.API_HOST, config.apiHost);
bundle.put(Keys.CDN_HOST, config.cdnHost);
- bundle.put(Keys.FLUSH_INTERVAL, StringUtils.fromInteger(config.flushInterval));
- bundle.put(Keys.FLUSH_AT, StringUtils.fromInteger(config.flushAt));
bundle.put(Keys.TRACK_SCREENS, StringUtils.fromBoolean(config.screenTrackingEnabled));
bundle.put(Keys.TRACK_DEVICE_ATTRIBUTES, StringUtils.fromBoolean(config.deviceAttributesTrackingEnabled));
- bundle.put(Keys.DEBUG_MODE, StringUtils.fromBoolean(config.debugModeEnabled));
+ bundle.put(Keys.LOG_LEVEL, config.logLevel.name());
+ bundle.put(Keys.REGION, config.getRegion().getCode());
+ bundle.put(Keys.TRACK_APPLICATION_LIFECYCLE, StringUtils.fromBoolean(config.applicationLifecycleTrackingEnabled));
+ bundle.put(Keys.TEST_MODE_ENABLED, StringUtils.fromBoolean(config.testModeEnabled));
+ bundle.put(Keys.IN_APP_MESSAGING_ENABLED, StringUtils.fromBoolean(config.inAppMessagingEnabled));
return bundle;
}
@@ -94,35 +105,38 @@ public static Map toMap(@NonNull CustomerIOSDKConfig config) {
private final String apiHost;
@Nullable
private final String cdnHost;
- @Nullable
- private final Integer flushInterval;
- @Nullable
- private final Integer flushAt;
- @Nullable
- private final Boolean screenTrackingEnabled;
- @Nullable
- private final Boolean deviceAttributesTrackingEnabled;
- @Nullable
- private final Boolean debugModeEnabled;
+ private final boolean screenTrackingEnabled;
+ private final boolean deviceAttributesTrackingEnabled;
+ @NonNull
+ private final CioLogLevel logLevel;
+ @NonNull
+ private final Region region;
+ private final boolean applicationLifecycleTrackingEnabled;
+ private final boolean testModeEnabled;
+ private final boolean inAppMessagingEnabled;
public CustomerIOSDKConfig(@NonNull String cdpApiKey,
@NonNull String siteId,
@Nullable String apiHost,
@Nullable String cdnHost,
- @Nullable Integer flushInterval,
- @Nullable Integer flushAt,
- @Nullable Boolean screenTrackingEnabled,
- @Nullable Boolean deviceAttributesTrackingEnabled,
- @Nullable Boolean debugModeEnabled) {
+ boolean screenTrackingEnabled,
+ boolean deviceAttributesTrackingEnabled,
+ @NonNull CioLogLevel logLevel,
+ @NonNull Region region,
+ boolean applicationLifecycleTrackingEnabled,
+ boolean testModeEnabled,
+ boolean inAppMessagingEnabled) {
this.cdpApiKey = cdpApiKey;
this.siteId = siteId;
this.apiHost = apiHost;
this.cdnHost = cdnHost;
- this.flushInterval = flushInterval;
- this.flushAt = flushAt;
this.screenTrackingEnabled = screenTrackingEnabled;
this.deviceAttributesTrackingEnabled = deviceAttributesTrackingEnabled;
- this.debugModeEnabled = debugModeEnabled;
+ this.logLevel = logLevel;
+ this.region = region;
+ this.applicationLifecycleTrackingEnabled = applicationLifecycleTrackingEnabled;
+ this.testModeEnabled = testModeEnabled;
+ this.inAppMessagingEnabled = inAppMessagingEnabled;
}
@NonNull
@@ -145,48 +159,33 @@ public String getCdnHost() {
return cdnHost;
}
- @Nullable
- public Integer getFlushInterval() {
- return flushInterval;
- }
-
- @Nullable
- public Integer getFlushAt() {
- return flushAt;
- }
-
-
- @Nullable
- public Boolean isScreenTrackingEnabled() {
+ public boolean isScreenTrackingEnabled() {
return screenTrackingEnabled;
}
- @Nullable
- public Boolean isDeviceAttributesTrackingEnabled() {
+ public boolean isDeviceAttributesTrackingEnabled() {
return deviceAttributesTrackingEnabled;
}
- @Nullable
- public Boolean isDebugModeEnabled() {
- return debugModeEnabled;
+ @NonNull
+ public CioLogLevel getLogLevel() {
+ return logLevel;
}
- /**
- * Features by default are nullable to help differentiate between default/null values and
- * values set by user.
- * Unwrapping nullable values here for ease of use by keeping single source of truth for whole
- * sample app.
- */
+ public boolean isTestModeEnabled() {
+ return testModeEnabled;
+ }
- public boolean screenTrackingEnabled() {
- return Boolean.FALSE != screenTrackingEnabled;
+ public boolean isInAppMessagingEnabled() {
+ return inAppMessagingEnabled;
}
- public boolean deviceAttributesTrackingEnabled() {
- return Boolean.FALSE != deviceAttributesTrackingEnabled;
+ public boolean isApplicationLifecycleTrackingEnabled() {
+ return applicationLifecycleTrackingEnabled;
}
- public boolean debugModeEnabled() {
- return Boolean.FALSE != debugModeEnabled;
+ @NonNull
+ public Region getRegion() {
+ return region;
}
}
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/sdk/CustomerIORepository.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/sdk/CustomerIORepository.java
index 952d64d25..05aa8a9be 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/sdk/CustomerIORepository.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/sdk/CustomerIORepository.java
@@ -16,8 +16,6 @@
import io.customer.messagingpush.ModuleMessagingPushFCM;
import io.customer.sdk.CustomerIO;
import io.customer.sdk.CustomerIOBuilder;
-import io.customer.sdk.core.util.CioLogLevel;
-import io.customer.sdk.data.model.Region;
/**
* Repository class to hold all Customer.io related operations at single place
@@ -31,24 +29,22 @@ public void initializeSdk(SampleApplication application) {
// Initialize Customer.io SDK builder
CustomerIOBuilder builder = new CustomerIOBuilder(application, sdkConfig.getCdpApiKey());
- // Enable detailed logging for debug builds.
- if (sdkConfig.debugModeEnabled()) {
- builder.logLevel(CioLogLevel.DEBUG);
- }
+ // Modify SDK settings for testing purposes only.
+ // If you don't need to override any of these settings, you can skip this line.
+ configureSdk(builder, sdkConfig);
// Enable optional features of the SDK by adding desired modules.
// Enables push notification
builder.addCustomerIOModule(new ModuleMessagingPushFCM());
- // Enables in-app messages
- builder.addCustomerIOModule(new ModuleMessagingInApp(
- new MessagingInAppModuleConfig.Builder(sdkConfig.getSiteId(), Region.US.INSTANCE)
- .setEventListener(new InAppMessageEventListener(appGraph.getLogger()))
- .build()
- ));
- // Modify SDK settings for testing purposes only.
- // If you don't need to override any of these settings, you can skip this line.
- configureSdk(builder, sdkConfig);
+ // Enables in-app messages
+ if (sdkConfig.isInAppMessagingEnabled()) {
+ builder.addCustomerIOModule(new ModuleMessagingInApp(
+ new MessagingInAppModuleConfig.Builder(sdkConfig.getSiteId(), sdkConfig.getRegion())
+ .setEventListener(new InAppMessageEventListener(appGraph.getLogger()))
+ .build()
+ ));
+ }
// Finally, build to finish initializing the SDK.
builder.build();
@@ -72,21 +68,15 @@ private void configureSdk(CustomerIOBuilder builder, final CustomerIOSDKConfig s
builder.cdnHost(cdnHost);
}
- if (sdkConfig.getFlushAt() != null) {
- builder.flushAt(sdkConfig.getFlushAt());
- }
- if (sdkConfig.getFlushInterval() != null) {
- builder.flushInterval(sdkConfig.getFlushInterval());
+ if (sdkConfig.isTestModeEnabled()) {
+ builder.flushAt(1);
}
- final Boolean screenTrackingEnabled = sdkConfig.isScreenTrackingEnabled();
- if (screenTrackingEnabled != null) {
- builder.autoTrackActivityScreens(screenTrackingEnabled);
- }
- final Boolean deviceAttributesTrackingEnabled = sdkConfig.isDeviceAttributesTrackingEnabled();
- if (deviceAttributesTrackingEnabled != null) {
- builder.autoTrackDeviceAttributes(deviceAttributesTrackingEnabled);
- }
+ builder.autoTrackActivityScreens(sdkConfig.isScreenTrackingEnabled());
+ builder.autoTrackDeviceAttributes(sdkConfig.isDeviceAttributesTrackingEnabled());
+ builder.trackApplicationLifecycleEvents(sdkConfig.isApplicationLifecycleTrackingEnabled());
+ builder.region(sdkConfig.getRegion());
+ builder.logLevel(sdkConfig.getLogLevel());
}
public void identify(@NonNull String email, @NonNull Map attributes) {
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/dashboard/DashboardActivity.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/dashboard/DashboardActivity.java
index 720231f78..de935a540 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/dashboard/DashboardActivity.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/dashboard/DashboardActivity.java
@@ -30,6 +30,7 @@
import io.customer.android.sample.java_layout.ui.common.SimpleFragmentActivity;
import io.customer.android.sample.java_layout.ui.core.BaseActivity;
import io.customer.android.sample.java_layout.ui.login.LoginActivity;
+import io.customer.android.sample.java_layout.ui.settings.InternalSettingsActivity;
import io.customer.android.sample.java_layout.ui.settings.SettingsActivity;
import io.customer.android.sample.java_layout.ui.user.AuthViewModel;
import io.customer.android.sample.java_layout.utils.Randoms;
@@ -109,6 +110,10 @@ private void setupViews() {
binding.settingsButton.setOnClickListener(view -> {
startActivity(new Intent(DashboardActivity.this, SettingsActivity.class));
});
+ binding.settingsButton.setOnLongClickListener(view -> {
+ startActivity(new Intent(DashboardActivity.this, InternalSettingsActivity.class));
+ return true;
+ });
binding.sendRandomEventButton.setOnClickListener(view -> {
sendRandomEvent();
});
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/login/LoginActivity.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/login/LoginActivity.java
index 7ee07c113..7a9e2b97d 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/login/LoginActivity.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/login/LoginActivity.java
@@ -9,6 +9,7 @@
import io.customer.android.sample.java_layout.databinding.ActivityLoginBinding;
import io.customer.android.sample.java_layout.ui.core.BaseActivity;
import io.customer.android.sample.java_layout.ui.dashboard.DashboardActivity;
+import io.customer.android.sample.java_layout.ui.settings.InternalSettingsActivity;
import io.customer.android.sample.java_layout.ui.settings.SettingsActivity;
import io.customer.android.sample.java_layout.ui.user.AuthViewModel;
import io.customer.android.sample.java_layout.utils.Randoms;
@@ -57,6 +58,10 @@ private void setupViews() {
binding.settingsButton.setOnClickListener(view -> {
startActivity(new Intent(LoginActivity.this, SettingsActivity.class));
});
+ binding.settingsButton.setOnLongClickListener(view -> {
+ startActivity(new Intent(LoginActivity.this, InternalSettingsActivity.class));
+ return true;
+ });
binding.loginButton.setOnClickListener(view -> {
boolean isFormValid = true;
String displayName = ViewUtils.getText(binding.displayNameTextInput);
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/InternalSettingsActivity.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/InternalSettingsActivity.java
new file mode 100644
index 000000000..f53260ff4
--- /dev/null
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/InternalSettingsActivity.java
@@ -0,0 +1,166 @@
+package io.customer.android.sample.java_layout.ui.settings;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+
+import io.customer.android.sample.java_layout.R;
+import io.customer.android.sample.java_layout.data.model.CustomerIOSDKConfig;
+import io.customer.android.sample.java_layout.databinding.ActivityInternalSettingsBinding;
+import io.customer.android.sample.java_layout.ui.core.BaseActivity;
+import io.customer.android.sample.java_layout.ui.dashboard.DashboardActivity;
+import io.customer.android.sample.java_layout.utils.OSUtils;
+import io.customer.android.sample.java_layout.utils.ViewUtils;
+import io.customer.sdk.CustomerIO;
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.disposables.CompositeDisposable;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+
+public class InternalSettingsActivity extends BaseActivity {
+
+ private SettingsViewModel settingsViewModel;
+ private final CompositeDisposable disposables = new CompositeDisposable();
+
+ @Override
+ protected ActivityInternalSettingsBinding inflateViewBinding() {
+ return ActivityInternalSettingsBinding.inflate(getLayoutInflater());
+ }
+
+ @Override
+ protected void injectDependencies() {
+ settingsViewModel = viewModelProvider.get(SettingsViewModel.class);
+ }
+
+ @Override
+ protected void setupContent() {
+ setUpObservers();
+ setUpActions();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ disposables.dispose();
+ }
+
+ private void setUpObservers() {
+ binding.settingsDeviceTokenLabel.setText(CustomerIO.instance().getRegisteredDeviceToken());
+ settingsViewModel.getSDKConfigObservable().observe(this, config -> {
+ binding.progressIndicator.hide();
+ updateUiWithConfig(config);
+ });
+ }
+
+ private void updateUiWithConfig(@NonNull CustomerIOSDKConfig config) {
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsApiHostLabel, config.getApiHost());
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsCdnHostLabel, config.getCdnHost());
+ }
+
+ private void setUpActions() {
+ binding.topAppBar.setNavigationOnClickListener(view -> {
+ // For better user experience, navigate to launcher activity on navigate up button
+ if (isTaskRoot()) {
+ startActivity(new Intent(InternalSettingsActivity.this, DashboardActivity.class));
+ }
+ onBackPressed();
+ });
+ binding.settingsDeviceTokenLayout.setEndIconOnClickListener(view -> {
+ String deviceToken = ViewUtils.getTextTrimmed(binding.settingsDeviceTokenLabel);
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getString(R.string.device_token), deviceToken);
+ clipboard.setPrimaryClip(clip);
+ Toast.makeText(this, R.string.token_copied, Toast.LENGTH_SHORT).show();
+ });
+ binding.settingsSaveButton.setOnClickListener(v -> saveSettings());
+ binding.settingsRestoreDefaultsButton.setOnClickListener(v -> updateUiWithConfig(CustomerIOSDKConfig.getDefaultConfigurations()));
+ ViewUtils.clearErrorWhenTextedEntered(binding.settingsApiHostLabel, binding.settingsApiHostLayout);
+ ViewUtils.clearErrorWhenTextedEntered(binding.settingsCdnHostLabel, binding.settingsCdnHostLayout);
+ }
+
+ private void saveSettings() {
+ CustomerIOSDKConfig currentSettings = settingsViewModel.getSDKConfigObservable().getValue();
+ if (currentSettings == null) {
+ Toast.makeText(this, "Error! Cannot save settings!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String apiHost = ViewUtils.getTextTrimmed(binding.settingsApiHostLabel);
+ String cdnHost = ViewUtils.getTextTrimmed(binding.settingsCdnHostLabel);
+ if (!validateUiInputs(apiHost, cdnHost)) {
+ return;
+ }
+
+ CustomerIOSDKConfig newSettings = createNewSettings(currentSettings, apiHost, cdnHost);
+ settingsViewModel.updateConfigurations(newSettings);
+
+ binding.progressIndicator.show();
+ Disposable disposable = settingsViewModel
+ .updateConfigurations(newSettings)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(preferences -> {
+ binding.progressIndicator.hide();
+ Toast.makeText(this, R.string.settings_save_msg, Toast.LENGTH_SHORT).show();
+ OSUtils.restartApp();
+ });
+ disposables.add(disposable);
+ }
+
+ private boolean validateUiInputs(@NonNull String apiHost, @NonNull String cdnHost) {
+ boolean valid = true;
+ if (isHostURLInvalid(apiHost)) {
+ valid = false;
+ ViewUtils.setError(binding.settingsApiHostLayout, getString(R.string.error_url_input_field));
+ }
+ if (isHostURLInvalid(cdnHost)) {
+ valid = false;
+ ViewUtils.setError(binding.settingsCdnHostLayout, getString(R.string.error_url_input_field));
+ }
+ return valid;
+ }
+
+ @NonNull
+ private static CustomerIOSDKConfig createNewSettings(CustomerIOSDKConfig currentSettings, String apiHost, String cdnHost) {
+ return new CustomerIOSDKConfig(
+ currentSettings.getCdpApiKey(),
+ currentSettings.getSiteId(),
+ apiHost,
+ cdnHost,
+ currentSettings.isScreenTrackingEnabled(),
+ currentSettings.isDeviceAttributesTrackingEnabled(),
+ currentSettings.getLogLevel(),
+ currentSettings.getRegion(),
+ currentSettings.isApplicationLifecycleTrackingEnabled(),
+ currentSettings.isTestModeEnabled(),
+ currentSettings.isInAppMessagingEnabled()
+ );
+ }
+
+ private boolean isHostURLInvalid(String url) {
+ // Empty text is not considered valid
+ if (TextUtils.isEmpty(url)) {
+ return true;
+ }
+
+ try {
+ Uri uri = Uri.parse(url);
+ // Since SDK does not support custom schemes, we manually append http:// to the URL
+ // So the URL is considered invalid if it ends with a slash, contains a scheme, query or fragment
+ return url.endsWith("/")
+ || !TextUtils.isEmpty(uri.getScheme())
+ || !TextUtils.isEmpty(uri.getQuery())
+ || !TextUtils.isEmpty(uri.getFragment());
+ } catch (Exception ex) {
+ //noinspection CallToPrintStackTrace
+ ex.printStackTrace();
+ return true;
+ }
+ }
+}
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/SettingsActivity.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/SettingsActivity.java
index df059b87f..aa237c585 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/SettingsActivity.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/ui/settings/SettingsActivity.java
@@ -1,8 +1,5 @@
package io.customer.android.sample.java_layout.ui.settings;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
@@ -19,9 +16,9 @@
import io.customer.android.sample.java_layout.ui.core.BaseActivity;
import io.customer.android.sample.java_layout.ui.dashboard.DashboardActivity;
import io.customer.android.sample.java_layout.utils.OSUtils;
-import io.customer.android.sample.java_layout.utils.StringUtils;
import io.customer.android.sample.java_layout.utils.ViewUtils;
-import io.customer.sdk.CustomerIO;
+import io.customer.sdk.core.util.CioLogLevel;
+import io.customer.sdk.data.model.Region;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
@@ -77,11 +74,11 @@ private void parseLinkParams() {
if (deepLinkUri != null) {
String cdpApiKey = deepLinkUri.getQueryParameter("cdp_api_key");
if (cdpApiKey != null) {
- ViewUtils.setTextWithSelectionIfFocused(binding.cdpApiKeyTextInput, cdpApiKey);
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsCdpApiKeyLabel, cdpApiKey);
}
String siteId = deepLinkUri.getQueryParameter("site_id");
if (siteId != null) {
- ViewUtils.setTextWithSelectionIfFocused(binding.siteIdTextInput, siteId);
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsSiteIdKeyLabel, siteId);
}
}
isLinkParamsPopulated = true;
@@ -89,18 +86,10 @@ private void parseLinkParams() {
private void prepareViewsForAutomatedTests() {
ViewUtils.prepareForAutomatedTests(binding.topAppBar);
- ViewUtils.prepareForAutomatedTests(binding.deviceTokenTextInput, R.string.acd_device_token_input);
- ViewUtils.prepareForAutomatedTests(binding.apiHostTextInput, R.string.acd_api_host_input);
- ViewUtils.prepareForAutomatedTests(binding.cdnHostTextInput, R.string.acd_cdn_host_input);
- ViewUtils.prepareForAutomatedTests(binding.cdpApiKeyTextInput, R.string.acd_cdp_api_key_input);
- ViewUtils.prepareForAutomatedTests(binding.siteIdTextInput, R.string.acd_site_id_input);
- ViewUtils.prepareForAutomatedTests(binding.flushIntervalTextInput, R.string.acd_flush_interval_input);
- ViewUtils.prepareForAutomatedTests(binding.flushAtTextInput, R.string.acd_flush_at_input);
- ViewUtils.prepareForAutomatedTests(binding.trackScreensSwitch, R.string.acd_track_screens_switch);
- ViewUtils.prepareForAutomatedTests(binding.trackDeviceAttributesSwitch, R.string.acd_track_device_attributes_switch);
- ViewUtils.prepareForAutomatedTests(binding.debugModeSwitch, R.string.acd_debug_mode_switch);
- ViewUtils.prepareForAutomatedTests(binding.saveButton, R.string.acd_save_settings_button);
- ViewUtils.prepareForAutomatedTests(binding.restoreDefaultsButton, R.string.acd_restore_default_settings_button);
+ ViewUtils.prepareForAutomatedTests(binding.settingsCdpApiKeyLabel, R.string.acd_cdp_api_key_input);
+ ViewUtils.prepareForAutomatedTests(binding.settingsSiteIdKeyLabel, R.string.acd_site_id_input);
+ ViewUtils.prepareForAutomatedTests(binding.settingsSaveButton, R.string.acd_save_settings_button);
+ ViewUtils.prepareForAutomatedTests(binding.settingsRestoreDefaultsButton, R.string.acd_restore_default_settings_button);
}
private void setupViews() {
@@ -111,24 +100,13 @@ private void setupViews() {
}
onBackPressed();
});
- binding.deviceTokenInputLayout.setEndIconOnClickListener(view -> {
- String deviceToken = ViewUtils.getTextTrimmed(binding.deviceTokenTextInput);
- ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText(getString(R.string.device_token), deviceToken);
- clipboard.setPrimaryClip(clip);
- Toast.makeText(this, R.string.token_copied, Toast.LENGTH_SHORT).show();
- });
- binding.saveButton.setOnClickListener(view -> saveSettings());
- binding.restoreDefaultsButton.setOnClickListener(view -> {
- updateIOWithConfig(CustomerIOSDKConfig.getDefaultConfigurations());
- saveSettings();
- });
+ binding.settingsSaveButton.setOnClickListener(view -> saveSettings());
+ binding.settingsRestoreDefaultsButton.setOnClickListener(view -> updateIOWithConfig(CustomerIOSDKConfig.getDefaultConfigurations()));
+ ViewUtils.clearErrorWhenTextedEntered(binding.settingsCdpApiKeyLabel, binding.settingsCdpApiKeyLayout);
+ ViewUtils.clearErrorWhenTextedEntered(binding.settingsSiteIdKeyLabel, binding.settingsSiteIdKeyLayout);
}
private void setupObservers() {
-
- binding.deviceTokenTextInput.setText(CustomerIO.instance().getRegisteredDeviceToken());
-
settingsViewModel.getSDKConfigObservable().observe(this, config -> {
binding.progressIndicator.hide();
updateIOWithConfig(config);
@@ -136,27 +114,6 @@ private void setupObservers() {
});
}
- private boolean isHostURLInvalid(String url) {
- // Empty text is not considered valid
- if (TextUtils.isEmpty(url)) {
- return true;
- }
-
- try {
- Uri uri = Uri.parse(url);
- // Since SDK does not support custom schemes, we manually append http:// to the URL
- // So the URL is considered invalid if it ends with a slash, contains a scheme, query or fragment
- return url.endsWith("/")
- || !TextUtils.isEmpty(uri.getScheme())
- || !TextUtils.isEmpty(uri.getQuery())
- || !TextUtils.isEmpty(uri.getFragment());
- } catch (Exception ex) {
- //noinspection CallToPrintStackTrace
- ex.printStackTrace();
- return true;
- }
- }
-
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private > boolean isNumberValid(T number, T min) {
// Compares if the value is not null and greater than or equal to min
@@ -165,70 +122,35 @@ private > boolean isNumberValid(T number, T min
}
private void updateIOWithConfig(@NonNull CustomerIOSDKConfig config) {
- ViewUtils.setTextWithSelectionIfFocused(binding.apiHostTextInput, config.getApiHost());
- ViewUtils.setTextWithSelectionIfFocused(binding.cdnHostTextInput, config.getCdnHost());
- ViewUtils.setTextWithSelectionIfFocused(binding.cdpApiKeyTextInput, config.getCdpApiKey());
- ViewUtils.setTextWithSelectionIfFocused(binding.siteIdTextInput, config.getSiteId());
- ViewUtils.setTextWithSelectionIfFocused(binding.flushIntervalTextInput, StringUtils.fromInteger(config.getFlushInterval()));
- ViewUtils.setTextWithSelectionIfFocused(binding.flushAtTextInput, StringUtils.fromInteger(config.getFlushAt()));
- binding.trackScreensSwitch.setChecked(config.screenTrackingEnabled());
- binding.trackDeviceAttributesSwitch.setChecked(config.deviceAttributesTrackingEnabled());
- binding.debugModeSwitch.setChecked(config.debugModeEnabled());
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsCdpApiKeyLabel, config.getCdpApiKey());
+ ViewUtils.setTextWithSelectionIfFocused(binding.settingsSiteIdKeyLabel, config.getSiteId());
+ binding.settingsRegionValuesGroup.check(getCheckedRegionButtonId(config.getRegion()));
+ binding.settingsTrackDeviceAttrsValuesGroup.check(getCheckedAutoTrackDeviceAttributesButtonId(config.isDeviceAttributesTrackingEnabled()));
+ binding.settingsTrackScreenViewsValuesGroup.check(getCheckedTrackScreenViewsButtonId(config.isScreenTrackingEnabled()));
+ binding.settingsTrackAppLifecycleValuesGroup.check(getCheckedTrackAppLifecycleButtonId(config.isApplicationLifecycleTrackingEnabled()));
+ binding.settingsLogLevelValuesGroup.check(getCheckedLogLevelButtonId(config.getLogLevel()));
+ binding.settingsTestModeValuesGroup.check(getCheckedTestModeButtonId(config.isTestModeEnabled()));
+ binding.settingsInAppMessagingValuesGroup.check(getCheckedInAppMessagingButtonId(config.isInAppMessagingEnabled()));
}
private void saveSettings() {
- boolean isFormValid;
-
- String apiHost = ViewUtils.getTextTrimmed(binding.apiHostTextInput);
- isFormValid = updateErrorState(binding.apiHostInputLayout, isHostURLInvalid(apiHost), R.string.error_host_url);
-
- String cdnHost = ViewUtils.getTextTrimmed(binding.cdnHostTextInput);
- isFormValid = updateErrorState(binding.cdnHostInputLayout, isHostURLInvalid(cdnHost), R.string.error_host_url) && isFormValid;
-
- String cdpApiKey = ViewUtils.getTextTrimmed(binding.cdpApiKeyTextInput);
- isFormValid = updateErrorState(binding.cdpApiKeyInputLayout, TextUtils.isEmpty(cdpApiKey), R.string.error_text_input_field_blank) && isFormValid;
+ CustomerIOSDKConfig currentSettings = settingsViewModel.getSDKConfigObservable().getValue();
+ if (currentSettings == null) {
+ Toast.makeText(this, "Error! Cannot save settings!", Toast.LENGTH_SHORT).show();
+ return;
+ }
- String siteId = ViewUtils.getTextTrimmed(binding.siteIdTextInput);
- isFormValid = updateErrorState(binding.siteIdInputLayout, TextUtils.isEmpty(siteId), R.string.error_text_input_field_blank) && isFormValid;
+ boolean isFormValid;
- String flushIntervalText = ViewUtils.getTextTrimmed(binding.flushIntervalTextInput);
- Integer flushInterval = StringUtils.parseInteger(flushIntervalText, null);
- boolean isFlushIntervalTextEmpty = TextUtils.isEmpty(flushIntervalText);
- if (isFlushIntervalTextEmpty) {
- isFormValid = updateErrorState(binding.flushIntervalInputLayout, true, R.string.error_text_input_field_blank) && isFormValid;
- } else {
- int minDelay = 1;
- isFormValid = updateErrorState(binding.flushIntervalInputLayout,
- !isNumberValid(flushInterval, minDelay),
- getString(R.string.error_number_input_field_small, String.valueOf(minDelay))) && isFormValid;
- }
+ String cdpApiKey = ViewUtils.getTextTrimmed(binding.settingsCdpApiKeyLabel);
+ isFormValid = updateErrorState(binding.settingsCdpApiKeyLayout, TextUtils.isEmpty(cdpApiKey), R.string.error_text_input_field_blank);
- String flushAtText = ViewUtils.getTextTrimmed(binding.flushAtTextInput);
- Integer flushAt = StringUtils.parseInteger(flushAtText, null);
- boolean isFlushAtTextEmpty = TextUtils.isEmpty(flushAtText);
- if (isFlushAtTextEmpty) {
- isFormValid = updateErrorState(binding.flushAtInputLayout, true, R.string.error_text_input_field_blank) && isFormValid;
- } else {
- int minTasks = 1;
- isFormValid = updateErrorState(binding.flushAtInputLayout,
- !isNumberValid(flushAt, minTasks),
- getString(R.string.error_number_input_field_small, String.valueOf(minTasks))) && isFormValid;
- }
+ String siteId = ViewUtils.getTextTrimmed(binding.settingsSiteIdKeyLabel);
+ isFormValid = updateErrorState(binding.settingsSiteIdKeyLayout, TextUtils.isEmpty(siteId), R.string.error_text_input_field_blank) && isFormValid;
if (isFormValid) {
binding.progressIndicator.show();
- boolean featTrackScreens = binding.trackScreensSwitch.isChecked();
- boolean featTrackDeviceAttributes = binding.trackDeviceAttributesSwitch.isChecked();
- boolean featDebugMode = binding.debugModeSwitch.isChecked();
- CustomerIOSDKConfig config = new CustomerIOSDKConfig(cdpApiKey,
- siteId,
- apiHost,
- cdnHost,
- flushInterval,
- flushAt,
- featTrackScreens,
- featTrackDeviceAttributes,
- featDebugMode);
+ CustomerIOSDKConfig config = createNewSettings(cdpApiKey, siteId, currentSettings);
Disposable disposable = settingsViewModel
.updateConfigurations(config)
.subscribeOn(Schedulers.io())
@@ -242,18 +164,102 @@ private void saveSettings() {
}
}
- private boolean updateErrorState(TextInputLayout textInputLayout,
- boolean isErrorEnabled,
- @StringRes int errorResId) {
- String error = isErrorEnabled ? getString(errorResId) : null;
- ViewUtils.setError(textInputLayout, error);
- return !isErrorEnabled;
+ @NonNull
+ private CustomerIOSDKConfig createNewSettings(String cdpApiKey, String siteId, CustomerIOSDKConfig currentSettings) {
+ boolean featTrackScreens = binding.settingsTrackScreenViewsValuesGroup.getCheckedButtonId() == R.id.settings_track_screen_views_yes_button;
+ boolean featTrackDeviceAttributes = binding.settingsTrackDeviceAttrsValuesGroup.getCheckedButtonId() == R.id.settings_track_device_attrs_yes_button;
+ boolean featTrackApplicationLifecycle = binding.settingsTrackAppLifecycleValuesGroup.getCheckedButtonId() == R.id.settings_track_app_lifecycle_yes_button;
+ boolean featTestModeEnabled = binding.settingsTestModeValuesGroup.getCheckedButtonId() == R.id.settings_test_mode_yes_button;
+ boolean featInAppMessagingEnabled = binding.settingsInAppMessagingValuesGroup.getCheckedButtonId() == R.id.settings_in_app_messaging_yes_button;
+ CioLogLevel logLevel = getSelectedLogLevel();
+ Region region = getSelectedRegion();
+
+ return new CustomerIOSDKConfig(cdpApiKey,
+ siteId,
+ currentSettings.getApiHost(),
+ currentSettings.getCdnHost(),
+ featTrackScreens,
+ featTrackDeviceAttributes,
+ logLevel,
+ region,
+ featTrackApplicationLifecycle,
+ featTestModeEnabled,
+ featInAppMessagingEnabled);
+ }
+
+ @NonNull
+ private CioLogLevel getSelectedLogLevel() {
+ int checkedButton = binding.settingsLogLevelValuesGroup.getCheckedButtonId();
+ if (checkedButton == R.id.settings_log_level_none_button) {
+ return CioLogLevel.NONE;
+ } else if (checkedButton == R.id.settings_log_level_error_button) {
+ return CioLogLevel.ERROR;
+ } else if (checkedButton == R.id.settings_log_level_info_button) {
+ return CioLogLevel.INFO;
+ } else if (checkedButton == R.id.settings_log_level_debug_button) {
+ return CioLogLevel.DEBUG;
+ }
+ throw new IllegalStateException();
+ }
+
+ @NonNull
+ private Region getSelectedRegion() {
+ int checkedButton = binding.settingsRegionValuesGroup.getCheckedButtonId();
+ if (checkedButton == R.id.settings_region_us_button) {
+ return Region.US.INSTANCE;
+ } else if (checkedButton == R.id.settings_region_eu_button) {
+ return Region.EU.INSTANCE;
+ }
+ throw new IllegalStateException();
+ }
+
+ private int getCheckedInAppMessagingButtonId(boolean enabled) {
+ return enabled ? R.id.settings_in_app_messaging_yes_button : R.id.settings_in_app_messaging_no_button;
+ }
+
+ private int getCheckedTestModeButtonId(boolean enabled) {
+ return enabled ? R.id.settings_test_mode_yes_button : R.id.settings_test_mode_no_button;
+ }
+
+ private int getCheckedLogLevelButtonId(@NonNull CioLogLevel logLevel) {
+ switch (logLevel) {
+ case NONE:
+ return R.id.settings_log_level_none_button;
+ case ERROR:
+ return R.id.settings_log_level_error_button;
+ case INFO:
+ return R.id.settings_log_level_info_button;
+ case DEBUG:
+ return R.id.settings_log_level_debug_button;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private int getCheckedTrackAppLifecycleButtonId(boolean enabled) {
+ return enabled ? R.id.settings_track_app_lifecycle_yes_button
+ : R.id.settings_track_app_lifecycle_no_button;
+ }
+
+ private int getCheckedTrackScreenViewsButtonId(boolean enabled) {
+ return enabled ? R.id.settings_track_screen_views_yes_button
+ : R.id.settings_track_screen_views_no_button;
+ }
+
+ private int getCheckedAutoTrackDeviceAttributesButtonId(boolean enabled) {
+ return enabled ? R.id.settings_track_device_attrs_yes_button
+ : R.id.settings_track_device_attrs_no_button;
+ }
+
+ private int getCheckedRegionButtonId(@NonNull Region region) {
+ return region instanceof Region.US ? R.id.settings_region_us_button
+ : R.id.settings_region_eu_button;
}
private boolean updateErrorState(TextInputLayout textInputLayout,
boolean isErrorEnabled,
- String errorMessage) {
- String error = isErrorEnabled ? errorMessage : null;
+ @StringRes int errorResId) {
+ String error = isErrorEnabled ? getString(errorResId) : null;
ViewUtils.setError(textInputLayout, error);
return !isErrorEnabled;
}
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/DefaultTextWatcher.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/DefaultTextWatcher.java
new file mode 100644
index 000000000..885aed239
--- /dev/null
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/DefaultTextWatcher.java
@@ -0,0 +1,25 @@
+package io.customer.android.sample.java_layout.utils;
+
+import android.text.Editable;
+import android.text.TextWatcher;
+
+/**
+ * Convenience class to prevent classes from having to override all methods and only override the
+ * ones desired.
+ */
+public class DefaultTextWatcher implements TextWatcher {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* NO OP */
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ /* NO OP */
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ /* NO OP */
+ }
+}
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/StringUtils.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/StringUtils.java
index bade5f226..966b83dd5 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/StringUtils.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/StringUtils.java
@@ -43,7 +43,7 @@ public static String fromInteger(@Nullable Integer value) {
return value == null ? null : value.toString();
}
- public static Boolean parseBoolean(@Nullable String value, Boolean defaultValue) {
+ public static Boolean parseBoolean(@Nullable String value, boolean defaultValue) {
if (TextUtils.isEmpty(value)) {
return defaultValue;
}
diff --git a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java
index ac8243efe..b5363d5d1 100644
--- a/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java
+++ b/samples/java_layout/src/main/java/io/customer/android/sample/java_layout/utils/ViewUtils.java
@@ -12,6 +12,7 @@
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import java.util.Locale;
@@ -70,4 +71,15 @@ public static MaterialAlertDialogBuilder createAlertDialog(@NonNull Activity act
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null);
}
+
+ public static void clearErrorWhenTextedEntered(@NonNull TextInputEditText editText,
+ @NonNull TextInputLayout textInputLayout) {
+ editText.addTextChangedListener(new DefaultTextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ textInputLayout.setError(null);
+ textInputLayout.setErrorEnabled(false);
+ }
+ });
+ }
}
diff --git a/samples/java_layout/src/main/res/layout/activity_internal_settings.xml b/samples/java_layout/src/main/res/layout/activity_internal_settings.xml
new file mode 100644
index 000000000..fe2ecd036
--- /dev/null
+++ b/samples/java_layout/src/main/res/layout/activity_internal_settings.xml
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/java_layout/src/main/res/layout/activity_settings.xml b/samples/java_layout/src/main/res/layout/activity_settings.xml
index 3b9063a4e..f448e50da 100644
--- a/samples/java_layout/src/main/res/layout/activity_settings.xml
+++ b/samples/java_layout/src/main/res/layout/activity_settings.xml
@@ -1,4 +1,5 @@
+
+ app:layout_constraintBottom_toTopOf="@id/settings_save_button"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_max="@dimen/material_text_field_max_width">
+ android:layout_height="wrap_content">
+
+
+ android:layout_marginTop="@dimen/margin_default"
+ android:hint="@string/cdp_api_key"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/settings_title_label">
+ android:layout_height="wrap_content" />
+
+ android:layout_marginTop="@dimen/margin_default"
+ android:hint="@string/site_id"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/settings_cdp_api_key_layout">
+ android:layout_height="wrap_content" />
+
-
+ android:layout_marginTop="@dimen/margin_default"
+ android:text="@string/region"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_site_id_key_layout" />
-
+
+
-
+ android:layout_weight="1"
+ android:text="@string/region_us" />
-
+
+
+
+ android:text="@string/track_device_attributes"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_region_values_group" />
-
+
+
-
+ android:layout_weight="1"
+ android:text="@string/settings_yes" />
-
+
+
+
+ android:layout_marginTop="@dimen/margin_default"
+ android:text="@string/track_screens"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_track_device_attrs_values_group" />
-
+
+
-
+ android:layout_weight="1"
+ android:text="@string/settings_yes" />
-
+
+
+
+ android:text="@string/track_application_lifecycle"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_track_screen_views_values_group" />
-
+
+
-
+ android:layout_weight="1"
+ android:text="@string/settings_yes" />
-
+
+
+
+ android:layout_marginTop="@dimen/margin_large"
+ android:text="@string/features"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_track_app_lifecycle_values_group" />
-
+
+
+
+
-
+ android:layout_weight="1"
+ android:text="@string/settings_yes" />
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+ android:text="@string/enable_test_mode_desc"
+ android:textAppearance="@style/TextAppearance.Material3.BodySmall"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/settings_test_mode_label" />
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/samples/java_layout/src/main/res/values-night/colors.xml b/samples/java_layout/src/main/res/values-night/colors.xml
new file mode 100644
index 000000000..5afae8157
--- /dev/null
+++ b/samples/java_layout/src/main/res/values-night/colors.xml
@@ -0,0 +1,143 @@
+
+ #A6CDD4
+ #0C363C
+ #002C32
+ #93B9C0
+ #FFFFFF
+ #213615
+ #C2DDAE
+ #304523
+ #D5BFE0
+ #392A44
+ #30223B
+ #C1ACCD
+ #FFB4AB
+ #690005
+ #93000A
+ #FFDAD6
+ #121414
+ #E2E2E2
+ #121414
+ #E2E2E2
+ #414849
+ #C1C8C9
+ #8B9293
+ #414849
+ #000000
+ #E2E2E2
+ #2F3131
+ #3F646B
+ #C2E9F1
+ #001F24
+ #A6CDD4
+ #264C52
+ #D0EBBB
+ #0D2003
+ #B5CEA1
+ #374D29
+ #F1DBFD
+ #24162E
+ #D5BFE0
+ #51415C
+ #121414
+ #38393A
+ #0D0E0F
+ #1A1C1C
+ #1E2020
+ #282A2B
+ #333535
+ #AAD1D9
+ #001A1E
+ #71979E
+ #000000
+ #FFFFFF
+ #213615
+ #C2DDAE
+ #112406
+ #D9C3E5
+ #1E1029
+ #9D8AA9
+ #000000
+ #FFBAB1
+ #370001
+ #FF5449
+ #000000
+ #121414
+ #E2E2E2
+ #121414
+ #FBFBFB
+ #414849
+ #C5CCCD
+ #9DA4A6
+ #7D8486
+ #000000
+ #E2E2E2
+ #282A2B
+ #284D54
+ #C2E9F1
+ #001417
+ #A6CDD4
+ #133B41
+ #D0EBBB
+ #041500
+ #B5CEA1
+ #273C1A
+ #F1DBFD
+ #190B23
+ #D5BFE0
+ #3F304B
+ #121414
+ #38393A
+ #0D0E0F
+ #1A1C1C
+ #1E2020
+ #282A2B
+ #333535
+ #F1FDFF
+ #000000
+ #AAD1D9
+ #000000
+ #FFFFFF
+ #000000
+ #C2DDAE
+ #000000
+ #FFF9FB
+ #000000
+ #D9C3E5
+ #000000
+ #FFF9F9
+ #000000
+ #FFBAB1
+ #000000
+ #121414
+ #E2E2E2
+ #121414
+ #FFFFFF
+ #414849
+ #F5FCFD
+ #C5CCCD
+ #C5CCCD
+ #000000
+ #E2E2E2
+ #000000
+ #032F35
+ #C6EEF5
+ #000000
+ #AAD1D9
+ #001A1E
+ #D4EFBF
+ #000000
+ #B9D3A5
+ #071B01
+ #F5E0FF
+ #000000
+ #D9C3E5
+ #1E1029
+ #121414
+ #38393A
+ #0D0E0F
+ #1A1C1C
+ #1E2020
+ #282A2B
+ #333535
+
diff --git a/samples/java_layout/src/main/res/values-night/themes.xml b/samples/java_layout/src/main/res/values-night/themes.xml
index 57c3379e3..b0e9fa149 100644
--- a/samples/java_layout/src/main/res/values-night/themes.xml
+++ b/samples/java_layout/src/main/res/values-night/themes.xml
@@ -1,31 +1,50 @@
-
diff --git a/samples/java_layout/src/main/res/values/colors.xml b/samples/java_layout/src/main/res/values/colors.xml
index afce3f1ff..28a000934 100644
--- a/samples/java_layout/src/main/res/values/colors.xml
+++ b/samples/java_layout/src/main/res/values/colors.xml
@@ -3,72 +3,150 @@
- #3C437D
- #4D57A9
- #FFFFFF
- #DFE0FF
- #000A64
- #8B5000
- #FFFFFF
- #FFDCBE
- #2C1600
- #00658F
- #FFFFFF
- #C7E7FF
- #001E2E
- #BA1A1A
- #FFDAD6
- #FFFFFF
- #410002
- #FFFBFF
- #1B1B1F
- #FFFBFF
- #1B1B1F
- #E3E1EC
- #46464F
- #777680
- #F3F0F4
- #303034
- #BCC2FF
- #000000
- #4D57A9
- #C7C5D0
- #000000
- #BCC2FF
- #1C2678
- #343E90
- #DFE0FF
- #FFB870
- #4A2800
- #693C00
- #FFDCBE
- #85CFFF
- #00344C
- #004C6C
- #C7E7FF
- #FFB4AB
- #93000A
- #690005
- #FFDAD6
- #1B1B1F
- #E4E1E6
- #1B1B1F
- #E4E1E6
- #46464F
- #C7C5D0
- #91909A
- #1B1B1F
- #E4E1E6
- #4D57A9
- #000000
- #BCC2FF
- #46464F
- #000000
+ #002328
+ #FFFFFF
+ #1E444A
+ #B3DAE2
+ #4E653F
+ #FFFFFF
+ #E9FFD6
+ #445A36
+ #261831
+ #FFFFFF
+ #483853
+ #E1CBEC
+ #BA1A1A
+ #FFFFFF
+ #FFDAD6
+ #410002
+ #F9F9F9
+ #1A1C1C
+ #F9F9F9
+ #1A1C1C
+ #DDE4E5
+ #414849
+ #71787A
+ #C1C8C9
+ #000000
+ #2F3131
+ #F1F1F1
+ #A6CDD4
+ #C2E9F1
+ #001F24
+ #A6CDD4
+ #264C52
+ #D0EBBB
+ #0D2003
+ #B5CEA1
+ #374D29
+ #F1DBFD
+ #24162E
+ #D5BFE0
+ #51415C
+ #DADADA
+ #F9F9F9
+ #FFFFFF
+ #F4F3F3
+ #EEEEEE
+ #E8E8E8
+ #E2E2E2
+ #002328
+ #FFFFFF
+ #1E444A
+ #FFFFFF
+ #334926
+ #FFFFFF
+ #647B54
+ #FFFFFF
+ #261831
+ #FFFFFF
+ #483853
+ #FFFFFF
+ #8C0009
+ #FFFFFF
+ #DA342E
+ #FFFFFF
+ #F9F9F9
+ #1A1C1C
+ #F9F9F9
+ #1A1C1C
+ #DDE4E5
+ #3D4445
+ #596062
+ #757C7D
+ #000000
+ #2F3131
+ #F1F1F1
+ #A6CDD4
+ #557B81
+ #FFFFFF
+ #3D6268
+ #FFFFFF
+ #647B54
+ #FFFFFF
+ #4C623D
+ #FFFFFF
+ #806E8C
+ #FFFFFF
+ #675672
+ #FFFFFF
+ #DADADA
+ #F9F9F9
+ #FFFFFF
+ #F4F3F3
+ #EEEEEE
+ #E8E8E8
+ #E2E2E2
+ #002328
+ #FFFFFF
+ #1E444A
+ #FFFFFF
+ #132708
+ #FFFFFF
+ #334926
+ #FFFFFF
+ #261831
+ #FFFFFF
+ #483853
+ #FFFFFF
+ #4E0002
+ #FFFFFF
+ #8C0009
+ #FFFFFF
+ #F9F9F9
+ #1A1C1C
+ #F9F9F9
+ #000000
+ #DDE4E5
+ #1E2526
+ #3D4445
+ #3D4445
+ #000000
+ #2F3131
+ #FFFFFF
+ #CBF3FB
+ #22484E
+ #FFFFFF
+ #063238
+ #FFFFFF
+ #334926
+ #FFFFFF
+ #1E3212
+ #FFFFFF
+ #4D3D58
+ #FFFFFF
+ #362741
+ #FFFFFF
+ #DADADA
+ #F9F9F9
+ #FFFFFF
+ #F4F3F3
+ #EEEEEE
+ #E8E8E8
+ #E2E2E2
- @color/md_theme_light_primary
+ @color/md_theme_primary
diff --git a/samples/java_layout/src/main/res/values/strings.xml b/samples/java_layout/src/main/res/values/strings.xml
index 13e5659ca..409e13cdb 100644
--- a/samples/java_layout/src/main/res/values/strings.xml
+++ b/samples/java_layout/src/main/res/values/strings.xml
@@ -7,6 +7,7 @@
LOGIN
Generate Random Login
Settings
+ Config settings
What would you like to test?
Send Random Event
Send Custom Event
@@ -25,9 +26,24 @@
flushInterval
flushAt
Features
+ Region
+ EU
+ US
Track Screens
Track Device Attributes
+ Track application lifecycle
Debug Mode
+ Yes
+ No
+ Enable in-app messages
+ Development
+ Log level
+ None
+ Error
+ Info
+ Debug
+ Enable test mode
+ (Sends events immediately without queuing)
Save
Restore Defaults
Note: App will restart automatically on Save
@@ -62,4 +78,9 @@
This field cannot be empty
The value must be greater than or equal to %1$s
Token Copied!
+
+
+ InternalSettingsActivity
+ This field must be a valid URL
+
diff --git a/samples/java_layout/src/main/res/values/styles.xml b/samples/java_layout/src/main/res/values/styles.xml
new file mode 100644
index 000000000..10a916a34
--- /dev/null
+++ b/samples/java_layout/src/main/res/values/styles.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/samples/java_layout/src/main/res/values/themes.xml b/samples/java_layout/src/main/res/values/themes.xml
index c45707d79..8fd04fad6 100644
--- a/samples/java_layout/src/main/res/values/themes.xml
+++ b/samples/java_layout/src/main/res/values/themes.xml
@@ -1,32 +1,52 @@