Skip to content

Commit ce6b49b

Browse files
authored
Merge pull request #1536 from OneSignal/feature/set_language_callbacks
Feature set language callbacks
2 parents 1086758 + 162fbf8 commit ce6b49b

File tree

5 files changed

+167
-8
lines changed

5 files changed

+167
-8
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import com.onesignal.influence.domain.OSInfluence;
5050
import com.onesignal.language.LanguageContext;
5151
import com.onesignal.language.LanguageProviderAppDefined;
52+
import com.onesignal.OneSignalStateSynchronizer.OSDeviceInfoError;
53+
import com.onesignal.OneSignalStateSynchronizer.OSDeviceInfoCompletionHandler;
5254
import com.onesignal.outcomes.data.OSOutcomeEventsFactory;
5355

5456
import org.json.JSONArray;
@@ -229,6 +231,25 @@ public static class SendTagsError {
229231
public String getMessage() { return message; }
230232
}
231233

234+
public static class OSLanguageError {
235+
private int errorCode;
236+
private String message;
237+
238+
OSLanguageError(int errorCode, String message) {
239+
this.errorCode = errorCode;
240+
this.message = message;
241+
}
242+
243+
public int getCode() { return errorCode; }
244+
245+
public String getMessage() { return message; }
246+
}
247+
248+
public interface OSSetLanguageCompletionHandler {
249+
void onSuccess(String results);
250+
void onFailure(OSLanguageError error);
251+
}
252+
232253
public enum ExternalIdErrorType {
233254
REQUIRES_EXTERNAL_ID_AUTH, INVALID_OPERATION, NETWORK
234255
}
@@ -1476,7 +1497,7 @@ private static void registerUserTask() throws JSONException {
14761497
deviceInfo.put("carrier", osUtils.getCarrierName());
14771498
deviceInfo.put("rooted", RootToolsInternalMethods.isRooted());
14781499

1479-
OneSignalStateSynchronizer.updateDeviceInfo(deviceInfo);
1500+
OneSignalStateSynchronizer.updateDeviceInfo(deviceInfo, null);
14801501

14811502
JSONObject pushState = new JSONObject();
14821503
pushState.put("identifier", lastRegistrationId);
@@ -1702,19 +1723,40 @@ public void run() {
17021723
}
17031724

17041725
public static void setLanguage(@NonNull final String language) {
1726+
setLanguage(language, null);
1727+
}
1728+
1729+
public static void setLanguage(@NonNull final String language, @Nullable final OSSetLanguageCompletionHandler completionCallback) {
17051730
if (taskRemoteController.shouldQueueTaskForInit(OSTaskRemoteController.SET_LANGUAGE)) {
17061731
logger.error("Waiting for remote params. " +
17071732
"Moving " + OSTaskRemoteController.SET_LANGUAGE + " operation to a pending task queue.");
17081733
taskRemoteController.addTaskToQueue(new Runnable() {
17091734
@Override
17101735
public void run() {
17111736
logger.debug("Running " + OSTaskRemoteController.SET_LANGUAGE + " operation from pending task queue.");
1712-
setLanguage(language);
1737+
setLanguage(language, completionCallback);
17131738
}
17141739
});
17151740
return;
17161741
}
17171742

1743+
OSDeviceInfoCompletionHandler deviceInfoCompletionHandler = null;
1744+
1745+
if(completionCallback != null) {
1746+
deviceInfoCompletionHandler = new OSDeviceInfoCompletionHandler() {
1747+
@Override
1748+
public void onSuccess(String results) {
1749+
completionCallback.onSuccess(results);
1750+
}
1751+
1752+
@Override
1753+
public void onFailure(OSDeviceInfoError error) {
1754+
OSLanguageError languageError = new OSLanguageError(error.errorCode, error.message);
1755+
completionCallback.onFailure(languageError);
1756+
}
1757+
};
1758+
}
1759+
17181760
if (shouldLogUserPrivacyConsentErrorMessageForMethodName(OSTaskRemoteController.SET_LANGUAGE))
17191761
return;
17201762

@@ -1725,7 +1767,7 @@ public void run() {
17251767
try {
17261768
JSONObject deviceInfo = new JSONObject();
17271769
deviceInfo.put("language", languageContext.getLanguage());
1728-
OneSignalStateSynchronizer.updateDeviceInfo(deviceInfo);
1770+
OneSignalStateSynchronizer.updateDeviceInfo(deviceInfo, deviceInfoCompletionHandler);
17291771
} catch (JSONException exception) {
17301772
exception.printStackTrace();
17311773
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,25 @@ public boolean isSMS() {
6060
}
6161
}
6262

63+
static class OSDeviceInfoError {
64+
public int errorCode;
65+
public String message;
66+
67+
OSDeviceInfoError(int errorCode, String message) {
68+
this.errorCode = errorCode;
69+
this.message = message;
70+
}
71+
72+
public int getCode() { return errorCode; }
73+
74+
public String getMessage() { return message; }
75+
}
76+
77+
interface OSDeviceInfoCompletionHandler {
78+
void onSuccess(String results);
79+
void onFailure(OSDeviceInfoError error);
80+
}
81+
6382
// Each class abstracts from UserStateSynchronizer and this will allow us to handle different channels for specific method calls and requests
6483
// Each time we create a new UserStateSynchronizer we should add it to the userStateSynchronizers HashMap
6584
// Currently we have 2 channels:
@@ -183,6 +202,10 @@ static void setSubscription(boolean enable) {
183202
static boolean getUserSubscribePreference() {
184203
return getPushStateSynchronizer().getUserSubscribePreference();
185204
}
205+
206+
static String getLanguage() {
207+
return getPushStateSynchronizer().getLanguage();
208+
}
186209

187210
static void setPermission(boolean enable) {
188211
getPushStateSynchronizer().setPermission(enable);
@@ -218,10 +241,10 @@ static void resetCurrentState() {
218241
OneSignal.setLastSessionTime(-60 * 61);
219242
}
220243

221-
static void updateDeviceInfo(JSONObject deviceInfo) {
222-
getPushStateSynchronizer().updateDeviceInfo(deviceInfo);
223-
getEmailStateSynchronizer().updateDeviceInfo(deviceInfo);
224-
getSMSStateSynchronizer().updateDeviceInfo(deviceInfo);
244+
static void updateDeviceInfo(JSONObject deviceInfo, OSDeviceInfoCompletionHandler handler) {
245+
getPushStateSynchronizer().updateDeviceInfo(deviceInfo, handler);
246+
getEmailStateSynchronizer().updateDeviceInfo(deviceInfo, handler);
247+
getSMSStateSynchronizer().updateDeviceInfo(deviceInfo, handler);
225248
}
226249

227250
static void updatePushState(JSONObject pushState) {

OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStatePushSynchronizer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ public boolean getUserSubscribePreference() {
158158
return getToSyncUserState().getDependValues().optBoolean(USER_SUBSCRIBE_PREF, true);
159159
}
160160

161+
public String getLanguage() {
162+
return getToSyncUserState().getDependValues().optString(LANGUAGE, null);
163+
}
164+
161165
@Override
162166
public void setPermission(boolean enable) {
163167
try {

OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import com.onesignal.OneSignal.ChangeTagsUpdateHandler;
99
import com.onesignal.OneSignal.SendTagsError;
1010
import com.onesignal.OneSignalStateSynchronizer.UserStateSynchronizerType;
11+
import com.onesignal.OneSignalStateSynchronizer.OSDeviceInfoCompletionHandler;
12+
import com.onesignal.OneSignalStateSynchronizer.OSDeviceInfoError;
1113

1214
import org.json.JSONException;
1315
import org.json.JSONObject;
@@ -37,6 +39,7 @@ abstract class UserStateSynchronizer {
3739
protected static final String ANDROID_PERMISSION = "androidPermission";
3840
protected static final String SUBSCRIBABLE_STATUS = "subscribableStatus";
3941
protected static final String TAGS = "tags";
42+
protected static final String LANGUAGE = "language";
4043
protected static final String EXTERNAL_USER_ID = "external_user_id";
4144
protected static final String EMAIL_KEY = "email";
4245
protected static final String LOGOUT_EMAIL = "logoutEmail";
@@ -92,6 +95,7 @@ String getRegistrationId() {
9295
// sendTags() multiple times it will call each callback
9396
final private Queue<ChangeTagsUpdateHandler> sendTagsHandlers = new ConcurrentLinkedQueue<>();
9497
final private Queue<OneSignal.OSInternalExternalUserIdUpdateCompletionHandler> externalUserIdUpdateHandlers = new ConcurrentLinkedQueue<>();
98+
final private Queue<OSDeviceInfoCompletionHandler> deviceInfoCompletionHandler = new ConcurrentLinkedQueue<>();
9599

96100
boolean hasQueuedHandlers() {
97101
return externalUserIdUpdateHandlers.size() > 0;
@@ -367,6 +371,9 @@ void onFailure(int statusCode, String response, Throwable throwable) {
367371
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "Error setting external user id for push with status code: " + statusCode + " and message: " + response);
368372
externalUserIdUpdateHandlersPerformOnFailure();
369373
}
374+
375+
if (jsonBody.has(LANGUAGE))
376+
deviceInfoHandlersPerformOnFailure(new OSDeviceInfoError(statusCode, response));
370377
}
371378

372379
@Override
@@ -381,6 +388,9 @@ void onSuccess(String response) {
381388

382389
if (jsonBody.has(EXTERNAL_USER_ID))
383390
externalUserIdUpdateHandlersPerformOnSuccess();
391+
392+
if (jsonBody.has(LANGUAGE))
393+
deviceInfoHandlersPerformOnSuccess();
384394
}
385395
});
386396
}
@@ -505,7 +515,9 @@ protected UserState getUserStateForModification() {
505515

506516
abstract protected void scheduleSyncToServer();
507517

508-
void updateDeviceInfo(JSONObject deviceInfo) {
518+
void updateDeviceInfo(JSONObject deviceInfo, @Nullable OSDeviceInfoCompletionHandler handler) {
519+
if (handler != null)
520+
this.deviceInfoCompletionHandler.add(handler);
509521
getUserStateForModification().generateJsonDiffFromIntoSyncValued(deviceInfo, null);
510522
}
511523

@@ -612,4 +624,18 @@ private void externalUserIdUpdateHandlersPerformOnFailure() {
612624
}
613625
}
614626

627+
private void deviceInfoHandlersPerformOnSuccess() {
628+
String language = OneSignalStateSynchronizer.getLanguage();
629+
OSDeviceInfoCompletionHandler handler;
630+
while ((handler = deviceInfoCompletionHandler.poll()) != null) {
631+
handler.onSuccess(language);
632+
}
633+
}
634+
635+
private void deviceInfoHandlersPerformOnFailure(OSDeviceInfoError error) {
636+
OSDeviceInfoCompletionHandler handler;
637+
while((handler = deviceInfoCompletionHandler.poll()) != null) {
638+
handler.onFailure(error);
639+
}
640+
}
615641
}

OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
import com.onesignal.OSSubscriptionStateChanges;
6262
import com.onesignal.OneSignal;
6363
import com.onesignal.OneSignal.ChangeTagsUpdateHandler;
64+
import com.onesignal.OneSignal.OSSetLanguageCompletionHandler;
65+
import com.onesignal.OneSignal.OSLanguageError;
6466
import com.onesignal.OneSignalPackagePrivateHelper;
6567
import com.onesignal.OneSignalShadowPackageManager;
6668
import com.onesignal.PermissionsActivity;
@@ -2779,6 +2781,68 @@ public void testSetLanguageOnSession() throws Exception {
27792781
assertEquals("fr", lastRequest.payload.getString("language"));
27802782
}
27812783

2784+
private static class TestSetLanguageHandler implements OSSetLanguageCompletionHandler {
2785+
private AtomicBoolean succeeded = new AtomicBoolean(false);
2786+
private AtomicBoolean failed = new AtomicBoolean(false);
2787+
2788+
@Override
2789+
public void onSuccess(String results) { succeeded.set(true); }
2790+
2791+
@Override
2792+
public void onFailure(OSLanguageError error) { failed.set(true); }
2793+
2794+
boolean getSucceeded() { return succeeded.get(); }
2795+
2796+
boolean getFailed() { return failed.get(); }
2797+
}
2798+
2799+
// Tests to make sure the onSuccess handler works
2800+
@Test
2801+
public void shouldSetLanguageWithResponse() throws Exception {
2802+
OneSignalInit();
2803+
threadAndTaskWait();
2804+
2805+
TestSetLanguageHandler handler = new TestSetLanguageHandler();
2806+
2807+
OneSignal.setLanguage("fr", handler);
2808+
2809+
threadAndTaskWait();
2810+
2811+
assertTrue(handler.getSucceeded());
2812+
2813+
// now test to make sure the handler still fires for a call to
2814+
// setLanguage() that modifies existing language
2815+
2816+
handler = new TestSetLanguageHandler();
2817+
2818+
OneSignal.setLanguage("es", handler);
2819+
2820+
threadAndTaskWait();
2821+
2822+
assertTrue(handler.getSucceeded());
2823+
}
2824+
2825+
// Tests to make sure that the onFailure callback works
2826+
@Test
2827+
public void shouldFailToSetLanguageWithResponse() throws Exception {
2828+
TestSetLanguageHandler handler = new TestSetLanguageHandler();
2829+
2830+
OneSignalInit();
2831+
threadAndTaskWait();
2832+
2833+
ShadowOneSignalRestClient.failMethod = "players";
2834+
ShadowOneSignalRestClient.failHttpCode = 403;
2835+
ShadowOneSignalRestClient.setNextFailureJSONResponse(new JSONObject() {{
2836+
put("tags", "error");
2837+
}});
2838+
2839+
// Should fail because players call failed with tags
2840+
OneSignal.setLanguage("fr", handler);
2841+
threadAndTaskWait();
2842+
2843+
assertTrue(handler.getFailed());
2844+
}
2845+
27822846
/**
27832847
* Similar workflow to testLocationPermissionPromptWithPrivacyConsent()
27842848
* We want to provide consent but make sure that session time tracking works properly

0 commit comments

Comments
 (0)