());
}
catch (JSONException t) {
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSDeviceState.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSDeviceState.java
index 83432171d8..d7089b35c1 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSDeviceState.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSDeviceState.java
@@ -35,12 +35,16 @@ public class OSDeviceState {
private final boolean pushDisabled;
private final boolean subscribed;
private final boolean emailSubscribed;
+ private final boolean smsSubscribed;
private final String userId;
private final String pushToken;
private final String emailUserId;
private final String emailAddress;
+ private final String smsUserId;
+ private final String smsNumber;
- OSDeviceState(OSSubscriptionState subscriptionStatus, OSPermissionState permissionStatus, OSEmailSubscriptionState emailSubscriptionStatus) {
+ OSDeviceState(OSSubscriptionState subscriptionStatus, OSPermissionState permissionStatus,
+ OSEmailSubscriptionState emailSubscriptionStatus, OSSMSSubscriptionState smsSubscriptionState) {
areNotificationsEnabled = permissionStatus.areNotificationsEnabled();
pushDisabled = subscriptionStatus.isPushDisabled();
subscribed = subscriptionStatus.isSubscribed();
@@ -49,6 +53,9 @@ public class OSDeviceState {
emailUserId = emailSubscriptionStatus.getEmailUserId();
emailAddress = emailSubscriptionStatus.getEmailAddress();
emailSubscribed = emailSubscriptionStatus.isSubscribed();
+ smsUserId = smsSubscriptionState.getSmsUserId();
+ smsNumber = smsSubscriptionState.getSMSNumber();
+ smsSubscribed = smsSubscriptionState.isSubscribed();
}
/**
@@ -123,6 +130,18 @@ public String getEmailAddress() {
return emailAddress;
}
+ public boolean isSMSSubscribed() {
+ return smsSubscribed;
+ }
+
+ public String getSMSUserId() {
+ return smsUserId;
+ }
+
+ public String getSMSNumber() {
+ return smsNumber;
+ }
+
public JSONObject toJSONObject() {
JSONObject mainObj = new JSONObject();
@@ -135,6 +154,9 @@ public JSONObject toJSONObject() {
mainObj.put("isEmailSubscribed", emailSubscribed);
mainObj.put("emailUserId", emailUserId);
mainObj.put("emailAddress", emailAddress);
+ mainObj.put("isSMSSubscribed", smsSubscribed);
+ mainObj.put("smsUserId", smsUserId);
+ mainObj.put("smsNumber", smsNumber);
} catch (Throwable t) {
t.printStackTrace();
}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionChangedInternalObserver.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionChangedInternalObserver.java
new file mode 100644
index 0000000000..4851a93bb8
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionChangedInternalObserver.java
@@ -0,0 +1,50 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2021 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.onesignal;
+
+class OSSMSSubscriptionChangedInternalObserver {
+ void changed(OSSMSSubscriptionState state) {
+ fireChangesToPublicObserver(state);
+ }
+
+ // Handles firing a public facing OSSMSSubscriptionStateChangesObserver
+ // 1. Generates a OSSMSSubscriptionStateChanges object and sets to and from states
+ // 2. Persists acknowledgement
+ // - Prevents duplicated events
+ // - Notifies if changes were made outside of the app
+ static void fireChangesToPublicObserver(OSSMSSubscriptionState state) {
+ OSSMSSubscriptionStateChanges stateChanges =
+ new OSSMSSubscriptionStateChanges(OneSignal.lastSMSSubscriptionState, (OSSMSSubscriptionState) state.clone());
+
+ boolean hasReceiver = OneSignal.getSMSSubscriptionStateChangesObserver().notifyChange(stateChanges);
+ if (hasReceiver) {
+ OneSignal.lastSMSSubscriptionState = (OSSMSSubscriptionState) state.clone();
+ OneSignal.lastSMSSubscriptionState.persistAsFrom();
+ }
+ }
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionObserver.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionObserver.java
new file mode 100644
index 0000000000..5679ac2594
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionObserver.java
@@ -0,0 +1,32 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2021 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.onesignal;
+
+public interface OSSMSSubscriptionObserver {
+ void onSMSSubscriptionChanged(OSSMSSubscriptionStateChanges stateChanges);
+}
\ No newline at end of file
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionState.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionState.java
new file mode 100644
index 0000000000..4b2c33c182
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionState.java
@@ -0,0 +1,148 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2021 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.onesignal;
+
+import androidx.annotation.NonNull;
+
+import org.json.JSONObject;
+
+public class OSSMSSubscriptionState implements Cloneable {
+
+ private static final String CHANGED_KEY = "changed";
+ private static final String SMS_USER_ID = "smsUserId";
+ private static final String SMS_NUMBER = "smsNumber";
+ private static final String SUBSCRIBED = "isSubscribed";
+
+ private OSObservable observable;
+ private String smsUserId;
+ private String smsNumber;
+
+ OSSMSSubscriptionState(boolean asFrom) {
+ observable = new OSObservable<>(CHANGED_KEY, false);
+
+ if (asFrom) {
+ smsUserId = OneSignalPrefs.getString(OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_ID_LAST, null);
+ smsNumber = OneSignalPrefs.getString(OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_NUMBER_LAST, null);
+ } else {
+ smsUserId = OneSignal.getSMSId();
+ smsNumber = OneSignalStateSynchronizer.getSMSStateSynchronizer().getRegistrationId();
+ }
+ }
+
+ void clearSMSAndId() {
+ boolean changed = smsUserId != null || smsNumber != null;
+ smsUserId = null;
+ smsNumber = null;
+ if (changed)
+ observable.notifyChange(this);
+ }
+
+ public String getSmsUserId() {
+ return smsUserId;
+ }
+
+ void setSMSUserId(@NonNull String id) {
+ boolean changed = false;
+ if (id == null)
+ changed = smsUserId != null;
+ else if (!id.equals(smsUserId))
+ changed = true;
+
+ smsUserId = id;
+ if (changed)
+ observable.notifyChange(this);
+ }
+
+ public String getSMSNumber() {
+ return smsNumber;
+ }
+
+ void setSMSNumber(@NonNull String number) {
+ boolean changed = !number.equals(smsNumber);
+ smsNumber = number;
+ if (changed)
+ observable.notifyChange(this);
+ }
+
+ public boolean isSubscribed() {
+ return smsUserId != null && smsNumber != null;
+ }
+
+ void persistAsFrom() {
+ OneSignalPrefs.saveString(OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_ID_LAST, smsUserId);
+ OneSignalPrefs.saveString(OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_NUMBER_LAST, smsNumber);
+ }
+
+ boolean compare(OSSMSSubscriptionState from) {
+ return !(smsUserId != null ? smsUserId : "").equals(from.smsUserId != null ? from.smsUserId : "")
+ || !(smsNumber != null ? smsNumber : "").equals(from.smsNumber != null ? from.smsNumber : "");
+ }
+
+ public OSObservable getObservable() {
+ return observable;
+ }
+
+ protected Object clone() {
+ try {
+ return super.clone();
+ } catch (Throwable t) {
+ }
+ return null;
+ }
+
+ public JSONObject toJSONObject() {
+ JSONObject mainObj = new JSONObject();
+
+ try {
+ if (smsUserId != null)
+ mainObj.put(SMS_USER_ID, smsUserId);
+ else
+ mainObj.put(SMS_USER_ID, JSONObject.NULL);
+
+ if (smsNumber != null)
+ mainObj.put(SMS_NUMBER, smsNumber);
+ else
+ mainObj.put(SMS_NUMBER, JSONObject.NULL);
+
+ mainObj.put(SUBSCRIBED, isSubscribed());
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return mainObj;
+ }
+
+ @Override
+ public String toString() {
+ return toJSONObject().toString();
+ }
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionStateChanges.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionStateChanges.java
new file mode 100644
index 0000000000..6495cce53b
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSSMSSubscriptionStateChanges.java
@@ -0,0 +1,67 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2021 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.onesignal;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class OSSMSSubscriptionStateChanges {
+ private OSSMSSubscriptionState from, to;
+
+ public OSSMSSubscriptionStateChanges(OSSMSSubscriptionState from, OSSMSSubscriptionState to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ public OSSMSSubscriptionState getTo() {
+ return to;
+ }
+
+ public OSSMSSubscriptionState getFrom() {
+ return from;
+ }
+
+ public JSONObject toJSONObject() {
+ JSONObject mainObj = new JSONObject();
+
+ try {
+ mainObj.put("from", from.toJSONObject());
+ mainObj.put("to", to.toJSONObject());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ return mainObj;
+ }
+
+ @Override
+ public String toString() {
+ return toJSONObject().toString();
+ }
+
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSTaskController.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSTaskController.java
index a11af7e2dc..2dd6a5ceb3 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSTaskController.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OSTaskController.java
@@ -17,7 +17,9 @@ class OSTaskController {
// Available task for delay
static final String GET_TAGS = "getTags()";
+ static final String SET_SMS_NUMBER = "setSMSNumber()";
static final String SET_EMAIL = "setEmail()";
+ static final String LOGOUT_SMS_NUMBER = "logoutSMSNumber()";
static final String LOGOUT_EMAIL = "logoutEmail()";
static final String SYNC_HASHED_EMAIL = "syncHashedEmail()";
static final String SET_EXTERNAL_USER_ID = "setExternalUserId()";
@@ -38,7 +40,9 @@ class OSTaskController {
static final String SEND_OUTCOME_WITH_VALUE = "sendOutcomeWithValue()";
static final HashSet METHODS_AVAILABLE_FOR_DELAY = new HashSet<>(Arrays.asList(
GET_TAGS,
+ SET_SMS_NUMBER,
SET_EMAIL,
+ LOGOUT_SMS_NUMBER,
LOGOUT_EMAIL,
SYNC_HASHED_EMAIL,
SET_EXTERNAL_USER_ID,
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java
index c140814908..6bc1d49799 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java
@@ -262,6 +262,36 @@ interface OSInternalExternalUserIdUpdateCompletionHandler {
void onComplete(String channel, boolean success);
}
+ public enum SMSErrorType {
+ VALIDATION, REQUIRES_SMS_AUTH, INVALID_OPERATION, NETWORK
+ }
+
+ public static class OSSMSUpdateError {
+ private SMSErrorType type;
+ private String message;
+
+ OSSMSUpdateError(SMSErrorType type, String message) {
+ this.type = type;
+ this.message = message;
+ }
+
+ public SMSErrorType getType() {
+ return type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+ }
+
+ public interface OSSMSUpdateHandler {
+ void onSuccess(JSONObject result);
+ void onFailure(OSSMSUpdateError error);
+ }
+
+ private static OSSMSUpdateHandler smsUpdateHandler;
+ private static OSSMSUpdateHandler smsLogoutHandler;
+
public enum EmailErrorType {
VALIDATION, REQUIRES_EMAIL_AUTH, INVALID_OPERATION, NETWORK
}
@@ -339,6 +369,7 @@ static Activity getCurrentActivity() {
private static String userId = null;
private static String emailId = null;
+ private static String smsId = null;
private static int subscribableStatus = Integer.MAX_VALUE;
static OSRemoteNotificationReceivedHandler remoteNotificationReceivedHandler;
@@ -536,6 +567,42 @@ static OSObservable smsSubscriptionStateChangesObserver;
+ static OSObservable getSMSSubscriptionStateChangesObserver() {
+ if (smsSubscriptionStateChangesObserver == null)
+ smsSubscriptionStateChangesObserver = new OSObservable<>("onSMSSubscriptionChanged", true);
+ return smsSubscriptionStateChangesObserver;
+ }
+ // End SMSSubscriptionState
+
/**
* Get the current user data, notification and permissions state.
*/
@@ -549,7 +616,8 @@ public static OSDeviceState getDeviceState() {
OSSubscriptionState subscriptionStatus = getCurrentSubscriptionState(appContext);
OSPermissionState permissionStatus = getCurrentPermissionState(appContext);
OSEmailSubscriptionState emailSubscriptionStatus = getCurrentEmailSubscriptionState(appContext);
- return new OSDeviceState(subscriptionStatus, permissionStatus, emailSubscriptionStatus);
+ OSSMSSubscriptionState smsSubscriptionStatus = getCurrentSMSSubscriptionState(appContext);
+ return new OSDeviceState(subscriptionStatus, permissionStatus, emailSubscriptionStatus, smsSubscriptionStatus);
}
private static class IAPUpdateJob {
@@ -1391,6 +1459,107 @@ private static void registerUserTask() throws JSONException {
waitingToPostStateSync = false;
}
+ public static void setSMSNumber(@NonNull final String smsNumber, OSSMSUpdateHandler callback) {
+ setSMSNumber(smsNumber, null, callback);
+ }
+
+ public static void setSMSNumber(@NonNull final String smsNumber) {
+ setSMSNumber(smsNumber, null, null);
+ }
+
+ public static void setSMSNumber(@NonNull final String smsNumber, @Nullable final String smsAuthHash) {
+ setSMSNumber(smsNumber, smsAuthHash, null);
+ }
+
+ /**
+ * Set an sms number for the device to later send sms to this number
+ * @param smsNumber The sms number that you want subscribe and associate with the device
+ * @param smsAuthHash Generated auth hash from your server to authorize. (Recommended)
+ * Create and send this hash from your backend to your app after
+ * the user logs into your app.
+ * DO NOT generate this from your app!
+ * Omit this value if you do not have a backend to authenticate the user.
+ * @param callback Fire onSuccess or onFailure depending if the update successes or fails
+ */
+ public static void setSMSNumber(@NonNull final String smsNumber, final String smsAuthHash, final OSSMSUpdateHandler callback) {
+ if (taskController.shouldQueueTaskForInit(OSTaskController.SET_SMS_NUMBER)) {
+ logger.error("Waiting for remote params. " +
+ "Moving " + OSTaskController.SET_SMS_NUMBER + " operation to a pending task queue.");
+ taskController.addTaskToQueue(new Runnable() {
+ @Override
+ public void run() {
+ logger.debug("Running " + OSTaskController.SET_SMS_NUMBER + " operation from a pending task queue.");
+ setSMSNumber(smsNumber, smsAuthHash, callback);
+ }
+ });
+ return;
+ }
+
+ // If applicable, check if the user provided privacy consent
+ if (shouldLogUserPrivacyConsentErrorMessageForMethodName(OSTaskController.SET_SMS_NUMBER))
+ return;
+
+ if (TextUtils.isEmpty(smsNumber)) {
+ String errorMessage = "SMS number is invalid";
+ if (callback != null)
+ callback.onFailure(new OSSMSUpdateError(SMSErrorType.VALIDATION, errorMessage));
+ logger.error(errorMessage);
+ return;
+ }
+
+ if (getRemoteParams().useSMSAuth && (smsAuthHash == null || smsAuthHash.length() == 0)) {
+ String errorMessage = "SMS authentication (auth token) is set to REQUIRED for this application. Please provide an auth token from your backend server or change the setting in the OneSignal dashboard.";
+ if (callback != null)
+ callback.onFailure(new OSSMSUpdateError(SMSErrorType.REQUIRES_SMS_AUTH, errorMessage));
+ logger.error(errorMessage);
+ return;
+ }
+
+ smsUpdateHandler = callback;
+
+ getCurrentSMSSubscriptionState(appContext).setSMSNumber(smsNumber);
+ OneSignalStateSynchronizer.setSMSNumber(smsNumber, smsAuthHash);
+ }
+
+ /**
+ * Call when user logs out of their account.
+ * This dissociates the device from the email address.
+ * This does not effect the subscription status of the email address itself.
+ */
+ public static void logoutSMSNumber() {
+ logoutSMSNumber(null);
+ }
+
+ public static void logoutSMSNumber(@Nullable final OSSMSUpdateHandler callback) {
+ if (taskController.shouldQueueTaskForInit(OSTaskController.LOGOUT_SMS_NUMBER)) {
+ logger.error("Waiting for remote params. " +
+ "Moving " + OSTaskController.LOGOUT_SMS_NUMBER + " operation to a pending task queue.");
+ taskController.addTaskToQueue(new Runnable() {
+ @Override
+ public void run() {
+ logger.debug("Running " + OSTaskController.LOGOUT_SMS_NUMBER + " operation from pending task queue.");
+ logoutSMSNumber(callback);
+ }
+ });
+ return;
+ }
+
+ // If applicable, check if the user provided privacy consent
+ if (shouldLogUserPrivacyConsentErrorMessageForMethodName(OSTaskController.LOGOUT_SMS_NUMBER))
+ return;
+
+ if (getSMSId() == null) {
+ final String message = OSTaskController.LOGOUT_SMS_NUMBER + " not valid as sms number was not set or already logged out!";
+ if (callback != null)
+ callback.onFailure(new OSSMSUpdateError(SMSErrorType.INVALID_OPERATION, message));
+ logger.error(message);
+ return;
+ }
+
+ smsLogoutHandler = callback;
+ OneSignalStateSynchronizer.logoutSMS();
+ }
+
public static void setEmail(@NonNull final String email, EmailUpdateHandler callback) {
setEmail(email, null, callback);
}
@@ -1970,9 +2139,7 @@ static void sendPurchases(JSONArray purchases, boolean newAsExisting, OneSignalR
jsonBody.put("existing", true);
jsonBody.put("purchases", purchases);
- OneSignalRestClient.post("players/" + getUserId() + "/on_purchase", jsonBody, responseHandler);
- if (getEmailId() != null)
- OneSignalRestClient.post("players/" + getEmailId() + "/on_purchase", jsonBody, null);
+ OneSignalStateSynchronizer.sendPurchases(jsonBody, responseHandler);
} catch (Throwable t) {
Log(LOG_LEVEL.ERROR, "Failed to generate JSON for sendPurchases.", t);
}
@@ -2337,6 +2504,35 @@ static void saveEmailId(String id) {
"".equals(emailId) ? null : emailId);
}
+ static boolean hasSMSlId() {
+ return !TextUtils.isEmpty(smsId);
+ }
+
+ static String getSMSId() {
+ if (smsId == null && appContext != null) {
+ smsId = OneSignalPrefs.getString(
+ OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_ID,
+ null);
+ }
+
+ if (TextUtils.isEmpty(smsId))
+ return null;
+
+ return smsId;
+ }
+
+ static void saveSMSId(String id) {
+ smsId = id;
+ if (appContext == null)
+ return;
+
+ OneSignalPrefs.saveString(
+ OneSignalPrefs.PREFS_ONESIGNAL,
+ OneSignalPrefs.PREFS_OS_SMS_ID,
+ "".equals(smsId) ? null : smsId);
+ }
+
// Called when a player id is returned from OneSignal
// Updates anything else that might have been waiting for this id.
static void updateUserIdDependents(String userId) {
@@ -2350,7 +2546,7 @@ static void updateUserIdDependents(String userId) {
iapUpdateJob = null;
}
- OneSignalStateSynchronizer.refreshEmailState();
+ OneSignalStateSynchronizer.refreshSecondaryChannelState();
OneSignalChromeTabAndroidFrame.setup(appId, userId, AdvertisingIdProviderGPS.getLastValue(), getRemoteParams());
}
@@ -2366,6 +2562,11 @@ static void updateEmailIdDependents(String emailId) {
}
}
+ static void updateSMSIdDependents(String smsId) {
+ saveSMSId(smsId);
+ getCurrentSMSSubscriptionState(appContext).setSMSUserId(smsId);
+ }
+
// Start Remote params getters
static boolean getFirebaseAnalyticsEnabled() {
return remoteParamController.getFirebaseAnalyticsEnabled();
@@ -2789,6 +2990,38 @@ public static void removeEmailSubscriptionObserver(@NonNull OSEmailSubscriptionO
getEmailSubscriptionStateChangesObserver().removeObserver(observer);
}
+ /**
+ * The {@link OSSMSSubscriptionObserver#onSMSSubscriptionChanged(OSSMSSubscriptionStateChanges)}
+ * method will be fired on the passed-in object when a sms subscription property changes.
+ *
+ * This includes the following events:
+ *
+ * - SMS number set
+ *
+ * - Getting a player/user ID from OneSignal
+ * @param observer the instance of {@link OSSubscriptionObserver} that acts as the observer
+ */
+ public static void addSMSSubscriptionObserver(@NonNull OSSMSSubscriptionObserver observer) {
+ if (appContext == null) {
+ logger.error("OneSignal.initWithContext has not been called. Could not add sms subscription observer");
+ return;
+ }
+
+ getSMSSubscriptionStateChangesObserver().addObserver(observer);
+
+ if (getCurrentSMSSubscriptionState(appContext).compare(getLastSMSSubscriptionState(appContext)))
+ OSSMSSubscriptionChangedInternalObserver.fireChangesToPublicObserver(getCurrentSMSSubscriptionState(appContext));
+ }
+
+ public static void removeSMSSubscriptionObserver(@NonNull OSSMSSubscriptionObserver observer) {
+ if (appContext == null) {
+ logger.error("OneSignal.initWithContext has not been called. Could not modify sms subscription observer");
+ return;
+ }
+
+ getSMSSubscriptionStateChangesObserver().removeObserver(observer);
+ }
+
/** In-App Message Triggers */
/**
@@ -3023,6 +3256,34 @@ static void fireEmailUpdateFailure() {
}
}
+ static void handleSuccessfulSMSlLogout(JSONObject result) {
+ if (smsLogoutHandler != null) {
+ smsLogoutHandler.onSuccess(result);
+ smsLogoutHandler = null;
+ }
+ }
+
+ static void handleFailedSMSLogout() {
+ if (smsLogoutHandler != null) {
+ smsLogoutHandler.onFailure(new OSSMSUpdateError(SMSErrorType.NETWORK, "Failed due to network failure. Will retry on next sync."));
+ smsLogoutHandler = null;
+ }
+ }
+
+ static void fireSMSUpdateSuccess(JSONObject result) {
+ if (smsUpdateHandler != null) {
+ smsUpdateHandler.onSuccess(result);
+ smsUpdateHandler = null;
+ }
+ }
+
+ static void fireSMSUpdateFailure() {
+ if (smsUpdateHandler != null) {
+ smsUpdateHandler.onFailure(new OSSMSUpdateError(SMSErrorType.NETWORK, "Failed due to network failure. Will retry on next sync."));
+ smsUpdateHandler = null;
+ }
+ }
+
@NonNull
static OSTime getTime() {
return time;
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalPrefs.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalPrefs.java
index fc1c7d460c..cdd39f4603 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalPrefs.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalPrefs.java
@@ -103,6 +103,10 @@ class OneSignalPrefs {
public static final String PREFS_OS_EMAIL_ID = "OS_EMAIL_ID";
public static final String PREFS_ONESIGNAL_EMAIL_ID_LAST = "PREFS_ONESIGNAL_EMAIL_ID_LAST";
public static final String PREFS_ONESIGNAL_EMAIL_ADDRESS_LAST = "PREFS_ONESIGNAL_EMAIL_ADDRESS_LAST";
+ // SMS
+ public static final String PREFS_OS_SMS_ID = "PREFS_OS_SMS_ID";
+ public static final String PREFS_OS_SMS_ID_LAST = "PREFS_OS_SMS_ID_LAST";
+ public static final String PREFS_OS_SMS_NUMBER_LAST = "PREFS_OS_SMS_NUMBER_LAST";
// In-App Messaging
public static final String PREFS_OS_CACHED_IAMS = "PREFS_OS_CACHED_IAMS";
public static final String PREFS_OS_DISMISSED_IAMS = "PREFS_OS_DISPLAYED_IAMS";
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalRemoteParams.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalRemoteParams.java
index 53cc552741..eb8423d9fc 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalRemoteParams.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalRemoteParams.java
@@ -75,6 +75,7 @@ public String toString() {
static class Params {
String googleProjectNumber;
boolean enterprise;
+ boolean useSMSAuth;
boolean useEmailAuth;
boolean useUserIdAuth;
JSONArray notificationChannels;
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java
index 6b6624f138..cf1989d13b 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java
@@ -34,13 +34,16 @@
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
class OneSignalStateSynchronizer {
enum UserStateSynchronizerType {
PUSH,
- EMAIL;
+ EMAIL,
+ SMS;
public boolean isPush() {
return this.equals(PUSH);
@@ -49,6 +52,10 @@ public boolean isPush() {
public boolean isEmail() {
return this.equals(EMAIL);
}
+
+ public boolean isSMS() {
+ return this.equals(SMS);
+ }
}
// Each class abstracts from UserStateSynchronizer and this will allow us to handle different channels for specific method calls and requests
@@ -56,6 +63,7 @@ public boolean isEmail() {
// Currently we have 2 channels:
// 1. Push
// 2. Email
+ // 3. SMS
// Add more channels...
private static HashMap userStateSynchronizers = new HashMap<>();
@@ -74,29 +82,61 @@ static UserStateEmailSynchronizer getEmailStateSynchronizer() {
return (UserStateEmailSynchronizer) userStateSynchronizers.get(UserStateSynchronizerType.EMAIL);
}
+
+ // #3 UserStateSynchronizer -> SMS Channel
+ static UserStateSMSSynchronizer getSMSStateSynchronizer() {
+ if (!userStateSynchronizers.containsKey(UserStateSynchronizerType.SMS) || userStateSynchronizers.get(UserStateSynchronizerType.SMS) == null)
+ userStateSynchronizers.put(UserStateSynchronizerType.SMS, new UserStateSMSSynchronizer());
+
+ return (UserStateSMSSynchronizer) userStateSynchronizers.get(UserStateSynchronizerType.SMS);
+ }
+
+ static List getUserStateSynchronizers() {
+ List userStateSynchronizers = new ArrayList<>();
+
+ userStateSynchronizers.add(getPushStateSynchronizer());
+
+ // Make sure we are only setting external user id for email when an email is actually set
+ if (OneSignal.hasEmailId())
+ userStateSynchronizers.add(getEmailStateSynchronizer());
+
+ // Make sure we are only setting external user id for sms when an sms is actually set
+ if (OneSignal.hasSMSlId())
+ userStateSynchronizers.add(getSMSStateSynchronizer());
+
+ return userStateSynchronizers;
+ }
static boolean persist() {
boolean pushPersisted = getPushStateSynchronizer().persist();
boolean emailPersisted = getEmailStateSynchronizer().persist();
+ boolean smsPersisted = getSMSStateSynchronizer().persist();
+
if (emailPersisted)
emailPersisted = getEmailStateSynchronizer().getRegistrationId() != null;
- return pushPersisted || emailPersisted;
+ if (smsPersisted)
+ smsPersisted = getSMSStateSynchronizer().getRegistrationId() != null;
+
+ return pushPersisted || emailPersisted || smsPersisted;
}
static void clearLocation() {
getPushStateSynchronizer().clearLocation();
getEmailStateSynchronizer().clearLocation();
+ getSMSStateSynchronizer().clearLocation();
}
static void initUserState() {
getPushStateSynchronizer().initUserState();
getEmailStateSynchronizer().initUserState();
+ getSMSStateSynchronizer().initUserState();
}
static void syncUserState(boolean fromSyncService) {
getPushStateSynchronizer().syncUserState(fromSyncService);
getEmailStateSynchronizer().syncUserState(fromSyncService);
+ getSMSStateSynchronizer().syncUserState(fromSyncService);
}
static void sendTags(JSONObject newTags, @Nullable ChangeTagsUpdateHandler handler) {
@@ -104,6 +144,7 @@ static void sendTags(JSONObject newTags, @Nullable ChangeTagsUpdateHandler handl
JSONObject jsonField = new JSONObject().put("tags", newTags);
getPushStateSynchronizer().sendTags(jsonField, handler);
getEmailStateSynchronizer().sendTags(jsonField, handler);
+ getSMSStateSynchronizer().sendTags(jsonField, handler);
} catch (JSONException e) {
if (handler != null)
handler.onFailure(new OneSignal.SendTagsError(-1, "Encountered an error attempting to serialize your tags into JSON: " + e.getMessage() + "\n" + e.getStackTrace()));
@@ -111,9 +152,14 @@ static void sendTags(JSONObject newTags, @Nullable ChangeTagsUpdateHandler handl
}
}
+ static void setSMSNumber(String smsNumber, String smsAuthHash) {
+ getPushStateSynchronizer().setSMSNumber(smsNumber, smsAuthHash);
+ getSMSStateSynchronizer().setChannelId(smsNumber, smsAuthHash);
+ }
+
static void setEmail(String email, String emailAuthHash) {
getPushStateSynchronizer().setEmail(email, emailAuthHash);
- getEmailStateSynchronizer().setEmail(email, emailAuthHash);
+ getEmailStateSynchronizer().setChannelId(email, emailAuthHash);
}
static void setSubscription(boolean enable) {
@@ -131,6 +177,7 @@ static void setPermission(boolean enable) {
static void updateLocation(LocationController.LocationPoint point) {
getPushStateSynchronizer().updateLocation(point);
getEmailStateSynchronizer().updateLocation(point);
+ getSMSStateSynchronizer().updateLocation(point);
}
static boolean getSubscribed() {
@@ -148,9 +195,11 @@ static UserStateSynchronizer.GetTagsResult getTags(boolean fromServer) {
static void resetCurrentState() {
getPushStateSynchronizer().resetCurrentState();
getEmailStateSynchronizer().resetCurrentState();
+ getSMSStateSynchronizer().resetCurrentState();
- OneSignal.saveUserId(null);
- OneSignal.saveEmailId(null);
+ getPushStateSynchronizer().saveChannelId(null);
+ getEmailStateSynchronizer().saveChannelId(null);
+ getSMSStateSynchronizer().saveChannelId(null);
OneSignal.setLastSessionTime(-60 * 61);
}
@@ -158,24 +207,28 @@ static void resetCurrentState() {
static void updateDeviceInfo(JSONObject deviceInfo) {
getPushStateSynchronizer().updateDeviceInfo(deviceInfo);
getEmailStateSynchronizer().updateDeviceInfo(deviceInfo);
+ getSMSStateSynchronizer().updateDeviceInfo(deviceInfo);
}
static void updatePushState(JSONObject pushState) {
getPushStateSynchronizer().updateState(pushState);
}
- static void refreshEmailState() {
+ static void refreshSecondaryChannelState() {
getEmailStateSynchronizer().refresh();
+ getSMSStateSynchronizer().refresh();
}
static void setNewSession() {
getPushStateSynchronizer().setNewSession();
getEmailStateSynchronizer().setNewSession();
+ getSMSStateSynchronizer().setNewSession();
}
static boolean getSyncAsNewSession() {
return getPushStateSynchronizer().getSyncAsNewSession() ||
- getEmailStateSynchronizer().getSyncAsNewSession();
+ getEmailStateSynchronizer().getSyncAsNewSession() ||
+ getSMSStateSynchronizer().getSyncAsNewSession();
}
static void setNewSessionForEmail() {
@@ -184,7 +237,12 @@ static void setNewSessionForEmail() {
static void logoutEmail() {
getPushStateSynchronizer().logoutEmail();
- getEmailStateSynchronizer().logoutEmail();
+ getEmailStateSynchronizer().logoutChannel();
+ }
+
+ static void logoutSMS() {
+ getSMSStateSynchronizer().logoutChannel();
+ getPushStateSynchronizer().logoutSMS();
}
static void setExternalUserId(String externalId, String externalIdAuthHash, final OneSignal.OSExternalUserIdUpdateCompletionHandler completionHandler) throws JSONException {
@@ -222,11 +280,17 @@ public void run() {
}
};
- getPushStateSynchronizer().setExternalUserId(externalId, externalIdAuthHash, handler);
+ List userStateSynchronizers = getUserStateSynchronizers();
+ for (UserStateSynchronizer userStateSynchronizer : userStateSynchronizers) {
+ userStateSynchronizer.setExternalUserId(externalId, externalIdAuthHash, handler);
+ }
+ }
- // Make sure we are only setting external user id for email when an email is actually set
- if (OneSignal.hasEmailId())
- getEmailStateSynchronizer().setExternalUserId(externalId, externalIdAuthHash, handler);
+ static void sendPurchases(JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) {
+ List userStateSynchronizers = getUserStateSynchronizers();
+ for (UserStateSynchronizer userStateSynchronizer : userStateSynchronizers) {
+ userStateSynchronizer.sendPurchases(jsonBody, responseHandler);
+ }
}
// This is to indicate that StateSynchronizer can start making REST API calls
@@ -235,6 +299,7 @@ public void run() {
static void readyToUpdate(boolean canMakeUpdates) {
getPushStateSynchronizer().readyToUpdate(canMakeUpdates);
getEmailStateSynchronizer().readyToUpdate(canMakeUpdates);
+ getSMSStateSynchronizer().readyToUpdate(canMakeUpdates);
}
}
\ No newline at end of file
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserState.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserState.java
index 6c53781c68..3622c51ff7 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserState.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserState.java
@@ -11,6 +11,11 @@
import java.util.Map;
import java.util.Set;
+import static com.onesignal.UserStateSynchronizer.APP_ID;
+import static com.onesignal.UserStateSynchronizer.EMAIL_AUTH_HASH_KEY;
+import static com.onesignal.UserStateSynchronizer.EXTERNAL_USER_ID_AUTH_HASH;
+import static com.onesignal.UserStateSynchronizer.SMS_AUTH_HASH_KEY;
+
abstract class UserState {
// Object to synchronize on to prevent concurrent modifications on syncValues and dependValues
@@ -21,6 +26,7 @@ abstract class UserState {
public static final int DEVICE_TYPE_FIREOS = 2;
public static final int DEVICE_TYPE_EMAIL = 11;
public static final int DEVICE_TYPE_HUAWEI = 13;
+ public static final int DEVICE_TYPE_SMS = 14;
public static final int PUSH_STATUS_SUBSCRIBED = 1;
static final int PUSH_STATUS_NO_PERMISSION = 0;
@@ -59,7 +65,7 @@ public ImmutableJSONObject getDependValues() {
return new ImmutableJSONObject();
}
- void setDependValues(JSONObject dependValues) {
+ public void setDependValues(JSONObject dependValues) {
synchronized (LOCK) {
this.dependValues = dependValues;
}
@@ -237,12 +243,14 @@ JSONObject generateJsonDiff(UserState newState, boolean isSessionCall) {
try {
// app_id required for all REST API calls
- if (!sendJson.has("app_id"))
- sendJson.put("app_id", syncValues.optString("app_id"));
- if (syncValues.has("email_auth_hash"))
- sendJson.put("email_auth_hash", syncValues.optString("email_auth_hash"));
- if (syncValues.has("external_user_id_auth_hash"))
- sendJson.put("external_user_id_auth_hash", syncValues.optString("external_user_id_auth_hash"));
+ if (!sendJson.has(APP_ID))
+ sendJson.put(APP_ID, syncValues.optString(APP_ID));
+ if (syncValues.has(EMAIL_AUTH_HASH_KEY))
+ sendJson.put(EMAIL_AUTH_HASH_KEY, syncValues.optString(EMAIL_AUTH_HASH_KEY));
+ if (syncValues.has(SMS_AUTH_HASH_KEY))
+ sendJson.put(SMS_AUTH_HASH_KEY, syncValues.optString(SMS_AUTH_HASH_KEY));
+ if (syncValues.has(EXTERNAL_USER_ID_AUTH_HASH))
+ sendJson.put(EXTERNAL_USER_ID_AUTH_HASH, syncValues.optString(EXTERNAL_USER_ID_AUTH_HASH));
} catch (JSONException e) {
e.printStackTrace();
}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateEmailSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateEmailSynchronizer.java
index a62f036cce..f6c8ff7a35 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateEmailSynchronizer.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateEmailSynchronizer.java
@@ -1,16 +1,13 @@
package com.onesignal;
-import androidx.annotation.Nullable;
-
import com.onesignal.OneSignalStateSynchronizer.UserStateSynchronizerType;
-import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
-class UserStateEmailSynchronizer extends UserStateSynchronizer {
+class UserStateEmailSynchronizer extends UserStateSecondaryChannelSynchronizer {
UserStateEmailSynchronizer() {
super(UserStateSynchronizerType.EMAIL);
@@ -22,144 +19,59 @@ protected UserState newUserState(String inPersistKey, boolean load) {
}
@Override
- protected OneSignal.LOG_LEVEL getLogLevel() {
- return OneSignal.LOG_LEVEL.INFO;
- }
-
- // Email subscription not readable from SDK
- @Override
- boolean getSubscribed() {
- return false;
- }
-
- // Email tags not readable from SDK
- @Override
- GetTagsResult getTags(boolean fromServer) {
- return null;
- }
-
- // Email external id not readable from SDK
- @Override
- @Nullable
- String getExternalId(boolean fromServer) {
- return null;
+ protected String getId() {
+ return OneSignal.getEmailId();
}
- // Email subscription not settable from SDK
@Override
- void setSubscription(boolean enable) {}
-
- // Email does not have a user preference on the SDK
- @Override
- public boolean getUserSubscribePreference() {
- return false;
+ void saveChannelId(String id) {
+ OneSignal.saveEmailId(id);
}
- // Email subscription not readable from SDK
@Override
- public void setPermission(boolean enable) {}
+ void logoutChannel() {
+ OneSignal.saveEmailId("");
- @Override
- void updateState(JSONObject state) {}
+ resetCurrentState();
+ getToSyncUserState().removeFromSyncValues(IDENTIFIER);
+ List keysToRemove = new ArrayList<>();
+ keysToRemove.add(EMAIL_AUTH_HASH_KEY);
+ keysToRemove.add(DEVICE_PLAYER_ID);
+ keysToRemove.add(EXTERNAL_USER_ID);
+ getToSyncUserState().removeFromSyncValues(keysToRemove);
+ getToSyncUserState().persistState();
- void refresh() {
- scheduleSyncToServer();
+ OneSignal.getEmailSubscriptionState().clearEmailAndId();
}
@Override
- protected void scheduleSyncToServer() {
- // Don't make a POST / PUT network call if we never set an email.
- boolean neverEmail = getId() == null && getRegistrationId() == null;
- if (neverEmail || OneSignal.getUserId() == null)
- return;
-
- getNetworkHandlerThread(NetworkHandlerThread.NETWORK_HANDLER_USERSTATE).runNewJobDelayed();
- }
-
- void setEmail(String email, String emailAuthHash) {
- UserState userState = getUserStateForModification();
- ImmutableJSONObject syncValues = userState.getSyncValues();
-
- boolean noChange = email.equals(syncValues.optString("identifier")) &&
- syncValues.optString("email_auth_hash").equals(emailAuthHash == null ? "" : emailAuthHash);
- if (noChange) {
- OneSignal.fireEmailUpdateSuccess();
- return;
- }
-
- String existingEmail = syncValues.optString("identifier", null);
-
- if (existingEmail == null)
- setNewSession();
-
- try {
- JSONObject emailJSON = new JSONObject();
- emailJSON.put("identifier", email);
-
- if (emailAuthHash != null)
- emailJSON.put("email_auth_hash", emailAuthHash);
-
- if (emailAuthHash == null) {
- if (existingEmail != null && !existingEmail.equals(email)) {
- OneSignal.saveEmailId("");
- resetCurrentState();
- setNewSession();
- }
- }
-
- userState.generateJsonDiffFromIntoSyncValued(emailJSON, null);
- scheduleSyncToServer();
- }
- catch (JSONException e) {
- e.printStackTrace();
- }
+ protected String getChannelKey() {
+ return EMAIL_KEY;
}
@Override
- protected String getId() {
- return OneSignal.getEmailId();
+ protected String getAuthHashKey() {
+ return EMAIL_AUTH_HASH_KEY;
}
@Override
- void updateIdDependents(String id) {
- OneSignal.updateEmailIdDependents(id);
+ protected int getDeviceType() {
+ return UserState.DEVICE_TYPE_EMAIL;
}
@Override
- protected void addOnSessionOrCreateExtras(JSONObject jsonBody) {
- try {
- jsonBody.put("device_type", UserState.DEVICE_TYPE_EMAIL);
- jsonBody.putOpt("device_player_id", OneSignal.getUserId());
- } catch (JSONException e) {
- e.printStackTrace();
- }
+ void fireUpdateSuccess(JSONObject result) {
+ OneSignal.fireEmailUpdateSuccess();
}
@Override
- void logoutEmail() {
- OneSignal.saveEmailId("");
-
- resetCurrentState();
- getToSyncUserState().removeFromSyncValues("identifier");
- List keysToRemove = new ArrayList<>();
- keysToRemove.add("email_auth_hash");
- keysToRemove.add("device_player_id");
- keysToRemove.add("external_user_id");
- getToSyncUserState().removeFromSyncValues(keysToRemove);
- getToSyncUserState().persistState();
-
- OneSignal.getEmailSubscriptionState().clearEmailAndId();
+ void fireUpdateFailure() {
+ OneSignal.fireEmailUpdateFailure();
}
@Override
- protected void fireEventsForUpdateFailure(JSONObject jsonFields) {
- if (jsonFields.has("identifier"))
- OneSignal.fireEmailUpdateFailure();
+ void updateIdDependents(String id) {
+ OneSignal.updateEmailIdDependents(id);
}
- @Override
- protected void onSuccessfulSync(JSONObject jsonFields) {
- if (jsonFields.has("identifier"))
- OneSignal.fireEmailUpdateSuccess();
- }
}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStatePushSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStatePushSynchronizer.java
index 3d9c0dfd82..903c1087e8 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStatePushSynchronizer.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStatePushSynchronizer.java
@@ -23,6 +23,11 @@ protected OneSignal.LOG_LEVEL getLogLevel() {
return OneSignal.LOG_LEVEL.ERROR;
}
+ @Override
+ void saveChannelId(String id) {
+ OneSignal.saveUserId(id);
+ }
+
@Override
boolean getSubscribed() {
return getToSyncUserState().isSubscribed();
@@ -49,13 +54,13 @@ void onSuccess(String responseStr) {
try {
JSONObject lastGetTagsResponse = new JSONObject(responseStr);
- if (lastGetTagsResponse.has("tags")) {
+ if (lastGetTagsResponse.has(TAGS)) {
synchronized(LOCK) {
- JSONObject dependDiff = generateJsonDiff(getCurrentUserState().getSyncValues().optJSONObject("tags"),
- getToSyncUserState().getSyncValues().optJSONObject("tags"),
+ JSONObject dependDiff = generateJsonDiff(getCurrentUserState().getSyncValues().optJSONObject(TAGS),
+ getToSyncUserState().getSyncValues().optJSONObject(TAGS),
null, null);
- getCurrentUserState().putOnSyncValues("tags", lastGetTagsResponse.optJSONObject("tags"));
+ getCurrentUserState().putOnSyncValues(TAGS, lastGetTagsResponse.optJSONObject(TAGS));
getCurrentUserState().persistState();
// Allow server side tags to overwrite local tags expect for any pending changes
@@ -72,14 +77,14 @@ void onSuccess(String responseStr) {
}
synchronized(LOCK) {
- return new GetTagsResult(serverSuccess, JSONUtils.getJSONObjectWithoutBlankValues(getToSyncUserState().getSyncValues(), "tags"));
+ return new GetTagsResult(serverSuccess, JSONUtils.getJSONObjectWithoutBlankValues(getToSyncUserState().getSyncValues(), TAGS));
}
}
@Override
@Nullable String getExternalId(boolean fromServer) {
synchronized(LOCK) {
- return getToSyncUserState().getSyncValues().optString("external_user_id", null);
+ return getToSyncUserState().getSyncValues().optString(EXTERNAL_USER_ID, null);
}
}
@@ -92,10 +97,10 @@ protected void scheduleSyncToServer() {
void updateState(JSONObject pushState) {
try {
JSONObject syncUpdate = new JSONObject();
- syncUpdate.putOpt("identifier", pushState.optString("identifier", null));
- if (pushState.has("device_type"))
- syncUpdate.put("device_type", pushState.optInt("device_type"));
- syncUpdate.putOpt("parent_player_id", pushState.optString("parent_player_id", null));
+ syncUpdate.putOpt(IDENTIFIER, pushState.optString(IDENTIFIER, null));
+ if (pushState.has(DEVICE_TYPE))
+ syncUpdate.put(DEVICE_TYPE, pushState.optInt(DEVICE_TYPE));
+ syncUpdate.putOpt(PARENT_PLAYER_ID, pushState.optString(PARENT_PLAYER_ID, null));
UserState userState = getUserStateForModification();
userState.generateJsonDiffFromIntoSyncValued(syncUpdate, null);
} catch(JSONException t) {
@@ -104,10 +109,10 @@ void updateState(JSONObject pushState) {
try {
JSONObject dependUpdate = new JSONObject();
- if (pushState.has("subscribableStatus"))
- dependUpdate.put("subscribableStatus", pushState.optInt("subscribableStatus"));
- if (pushState.has("androidPermission"))
- dependUpdate.put("androidPermission", pushState.optBoolean("androidPermission"));
+ if (pushState.has(SUBSCRIBABLE_STATUS))
+ dependUpdate.put(SUBSCRIBABLE_STATUS, pushState.optInt(SUBSCRIBABLE_STATUS));
+ if (pushState.has(ANDROID_PERMISSION))
+ dependUpdate.put(ANDROID_PERMISSION, pushState.optBoolean(ANDROID_PERMISSION));
UserState userState = getUserStateForModification();
userState.generateJsonDiffFromIntoDependValues(dependUpdate, null);
@@ -120,18 +125,29 @@ void setEmail(String email, String emailAuthHash) {
try {
UserState userState = getUserStateForModification();
- userState.putOnDependValues("email_auth_hash", emailAuthHash);
- userState.generateJsonDiffFromIntoSyncValued(new JSONObject().put("email", email), null);
+ userState.putOnDependValues(EMAIL_AUTH_HASH_KEY, emailAuthHash);
+ userState.generateJsonDiffFromIntoSyncValued(new JSONObject().put(EMAIL_KEY, email), null);
}
catch (JSONException e) {
e.printStackTrace();
}
}
+ void setSMSNumber(String smsNumber, String smsAuthHash) {
+ try {
+ UserState userState = getUserStateForModification();
+
+ userState.putOnDependValues(SMS_AUTH_HASH_KEY, smsAuthHash);
+ userState.generateJsonDiffFromIntoSyncValued(new JSONObject().put(SMS_NUMBER_KEY, smsNumber), null);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
@Override
void setSubscription(boolean enable) {
try {
- getUserStateForModification().putOnDependValues("userSubscribePref", enable);
+ getUserStateForModification().putOnDependValues(USER_SUBSCRIBE_PREF, enable);
} catch (JSONException e) {
e.printStackTrace();
}
@@ -139,13 +155,13 @@ void setSubscription(boolean enable) {
@Override
public boolean getUserSubscribePreference() {
- return getToSyncUserState().getDependValues().optBoolean("userSubscribePref", true);
+ return getToSyncUserState().getDependValues().optBoolean(USER_SUBSCRIBE_PREF, true);
}
@Override
public void setPermission(boolean enable) {
try {
- getUserStateForModification().putOnDependValues("androidPermission", enable);
+ getUserStateForModification().putOnDependValues(ANDROID_PERMISSION, enable);
} catch (JSONException e) {
e.printStackTrace();
}
@@ -165,23 +181,63 @@ void updateIdDependents(String id) {
protected void addOnSessionOrCreateExtras(JSONObject jsonBody) {}
@Override
+ void logoutChannel() {
+ }
+
void logoutEmail() {
try {
- getUserStateForModification().putOnDependValues("logoutEmail", true);
+ getUserStateForModification().putOnDependValues(LOGOUT_EMAIL, true);
} catch (JSONException e) {
e.printStackTrace();
}
}
+ void logoutSMS() {
+ UserState toSyncUserState = getToSyncUserState();
+ toSyncUserState.removeFromDependValues(SMS_AUTH_HASH_KEY);
+ toSyncUserState.removeFromSyncValues(SMS_NUMBER_KEY);
+ toSyncUserState.persistState();
+
+ UserState currentUserState = getCurrentUserState();
+ currentUserState.removeFromDependValues(SMS_AUTH_HASH_KEY);
+ String smsNumberLoggedOut = currentUserState.getSyncValues().optString(SMS_NUMBER_KEY);
+ currentUserState.removeFromSyncValues(SMS_NUMBER_KEY);
+
+ JSONObject result = new JSONObject();
+ try {
+ result.put(SMS_NUMBER_KEY, smsNumberLoggedOut);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ OneSignal.Log(OneSignal.LOG_LEVEL.INFO, "Device successfully logged out of SMS number: " + result);
+ OneSignal.handleSuccessfulSMSlLogout(result);
+ }
+
@Override
protected void fireEventsForUpdateFailure(JSONObject jsonFields) {
- if (jsonFields.has("email"))
+ if (jsonFields.has(EMAIL_KEY))
OneSignal.fireEmailUpdateFailure();
+
+ if (jsonFields.has(SMS_NUMBER_KEY))
+ OneSignal.fireSMSUpdateFailure();
}
@Override
protected void onSuccessfulSync(JSONObject jsonFields) {
- if (jsonFields.has("email"))
+ if (jsonFields.has(EMAIL_KEY))
OneSignal.fireEmailUpdateSuccess();
+
+ if (jsonFields.has(SMS_NUMBER_KEY)) {
+ JSONObject result = new JSONObject();
+ try {
+ result.put(SMS_NUMBER_KEY, jsonFields.get(SMS_NUMBER_KEY));
+ if (jsonFields.has(SMS_AUTH_HASH_KEY))
+ result.put(SMS_AUTH_HASH_KEY, jsonFields.get(SMS_AUTH_HASH_KEY));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ OneSignal.fireSMSUpdateSuccess(result);
+ }
}
}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMS.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMS.java
new file mode 100644
index 0000000000..da822632f0
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMS.java
@@ -0,0 +1,26 @@
+package com.onesignal;
+
+class UserStateSMS extends UserState {
+
+ private static final String SMS = "sms";
+
+ UserStateSMS(String inPersistKey, boolean load) {
+ super(SMS + inPersistKey, load);
+ }
+
+ @Override
+ UserState newInstance(String persistKey) {
+ return new UserStateSMS(persistKey, false);
+ }
+
+ @Override
+ protected void addDependFields() {
+ // No depended fields for sms
+ }
+
+ @Override
+ boolean isSubscribed() {
+ // No subscription setting, always true
+ return true;
+ }
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMSSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMSSynchronizer.java
new file mode 100644
index 0000000000..524f7ec880
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSMSSynchronizer.java
@@ -0,0 +1,75 @@
+package com.onesignal;
+
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserStateSMSSynchronizer extends UserStateSecondaryChannelSynchronizer {
+
+ UserStateSMSSynchronizer() {
+ super(OneSignalStateSynchronizer.UserStateSynchronizerType.SMS);
+ }
+
+ @Override
+ protected UserState newUserState(String inPersistKey, boolean load) {
+ return new UserStateSMS(inPersistKey, load);
+ }
+
+ @Override
+ protected String getId() {
+ return OneSignal.getSMSId();
+ }
+
+ @Override
+ void saveChannelId(String id) {
+ OneSignal.saveSMSId(id);
+ }
+
+ @Override
+ void logoutChannel() {
+ saveChannelId("");
+
+ resetCurrentState();
+ getToSyncUserState().removeFromSyncValues(IDENTIFIER);
+ List keysToRemove = new ArrayList<>();
+ keysToRemove.add(SMS_AUTH_HASH_KEY);
+ keysToRemove.add(DEVICE_PLAYER_ID);
+ keysToRemove.add(EXTERNAL_USER_ID);
+ getToSyncUserState().removeFromSyncValues(keysToRemove);
+ getToSyncUserState().persistState();
+
+ OneSignal.getSMSSubscriptionState().clearSMSAndId();
+ }
+
+ @Override
+ protected String getChannelKey() {
+ return SMS_NUMBER_KEY;
+ }
+
+ @Override
+ protected String getAuthHashKey() {
+ return SMS_AUTH_HASH_KEY;
+ }
+
+ @Override
+ protected int getDeviceType() {
+ return UserState.DEVICE_TYPE_SMS;
+ }
+
+ @Override
+ void fireUpdateSuccess(JSONObject result) {
+ OneSignal.fireSMSUpdateSuccess(result);
+ }
+
+ @Override
+ void fireUpdateFailure() {
+ OneSignal.fireSMSUpdateFailure();
+ }
+
+ @Override
+ void updateIdDependents(String id) {
+ OneSignal.updateSMSIdDependents(id);
+ }
+
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSecondaryChannelSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSecondaryChannelSynchronizer.java
new file mode 100644
index 0000000000..eeadbd6ec1
--- /dev/null
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSecondaryChannelSynchronizer.java
@@ -0,0 +1,168 @@
+package com.onesignal;
+
+import androidx.annotation.Nullable;
+
+import com.onesignal.OneSignalStateSynchronizer.UserStateSynchronizerType;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+abstract class UserStateSecondaryChannelSynchronizer extends UserStateSynchronizer {
+
+ UserStateSecondaryChannelSynchronizer(UserStateSynchronizerType channel) {
+ super(channel);
+ }
+
+ @Override
+ protected abstract UserState newUserState(String inPersistKey, boolean load);
+
+ @Override
+ abstract protected String getId();
+
+ @Override
+ abstract void logoutChannel();
+
+ abstract protected String getChannelKey();
+ abstract protected String getAuthHashKey();
+
+ abstract protected int getDeviceType();
+
+ abstract void fireUpdateSuccess(JSONObject result);
+
+ abstract void fireUpdateFailure();
+
+ @Override
+ abstract void updateIdDependents(String id);
+
+ @Override
+ protected OneSignal.LOG_LEVEL getLogLevel() {
+ return OneSignal.LOG_LEVEL.INFO;
+ }
+
+ // Secondary channel subscriptions are not readable from SDK
+ @Override
+ boolean getSubscribed() {
+ return false;
+ }
+
+ // Secondary channel tags not readable from SDK
+ @Override
+ GetTagsResult getTags(boolean fromServer) {
+ return null;
+ }
+
+ // Secondary channel external id not readable from SDK
+ @Override
+ @Nullable
+ String getExternalId(boolean fromServer) {
+ return null;
+ }
+
+ // Secondary channel subscription not settable from SDK
+ @Override
+ void setSubscription(boolean enable) {}
+
+ // Secondary channel does not have a user preference on the SDK
+ @Override
+ public boolean getUserSubscribePreference() {
+ return false;
+ }
+
+ // Secondary channel subscription not readable from SDK
+ @Override
+ public void setPermission(boolean enable) {}
+
+ @Override
+ void updateState(JSONObject state) {}
+
+ void refresh() {
+ scheduleSyncToServer();
+ }
+
+ @Override
+ protected void scheduleSyncToServer() {
+ // Don't make a POST / PUT network call if we never set an email/SMS.
+ boolean userNotRegistered = getId() == null && getRegistrationId() == null;
+ if (userNotRegistered || OneSignal.getUserId() == null)
+ return;
+
+ getNetworkHandlerThread(NetworkHandlerThread.NETWORK_HANDLER_USERSTATE).runNewJobDelayed();
+ }
+
+ @Override
+ protected void addOnSessionOrCreateExtras(JSONObject jsonBody) {
+ try {
+ jsonBody.put(DEVICE_TYPE, getDeviceType());
+ jsonBody.putOpt(DEVICE_PLAYER_ID, OneSignal.getUserId());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void fireEventsForUpdateFailure(JSONObject jsonFields) {
+ if (jsonFields.has(IDENTIFIER))
+ fireUpdateFailure();
+ }
+
+ @Override
+ protected void onSuccessfulSync(JSONObject jsonFields) {
+ if (jsonFields.has(IDENTIFIER)) {
+ JSONObject result = new JSONObject();
+ try {
+ result.put(getChannelKey(), jsonFields.get(IDENTIFIER));
+ if (jsonFields.has(getAuthHashKey()))
+ result.put(getAuthHashKey(), jsonFields.get(getAuthHashKey()));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ fireUpdateSuccess(result);
+ }
+ }
+
+ void setChannelId(String id, String idAuthHash) {
+ UserState userState = getUserStateForModification();
+ ImmutableJSONObject syncValues = userState.getSyncValues();
+
+ boolean noChange = id.equals(syncValues.optString(IDENTIFIER)) &&
+ syncValues.optString(getAuthHashKey()).equals(idAuthHash == null ? "" : idAuthHash);
+ if (noChange) {
+ JSONObject result = new JSONObject();
+ try {
+ result.put(getChannelKey(), id);
+ result.put(getAuthHashKey(), idAuthHash);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ fireUpdateSuccess(result);
+ return;
+ }
+
+ String existingEmail = syncValues.optString(IDENTIFIER, null);
+
+ if (existingEmail == null)
+ setNewSession();
+
+ try {
+ JSONObject emailJSON = new JSONObject();
+ emailJSON.put(IDENTIFIER, id);
+
+ if (idAuthHash != null)
+ emailJSON.put(getAuthHashKey(), idAuthHash);
+
+ if (idAuthHash == null) {
+ if (existingEmail != null && !existingEmail.equals(id)) {
+ saveChannelId("");
+ resetCurrentState();
+ setNewSession();
+ }
+ }
+
+ userState.generateJsonDiffFromIntoSyncValued(emailJSON, null);
+ scheduleSyncToServer();
+ }
+ catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java
index 38957e25a7..d882f97569 100644
--- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java
+++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java
@@ -2,6 +2,7 @@
import android.os.Handler;
import android.os.HandlerThread;
+
import androidx.annotation.Nullable;
import com.onesignal.OneSignal.ChangeTagsUpdateHandler;
@@ -22,6 +23,30 @@
abstract class UserStateSynchronizer {
+ private static final String CURRENT_STATE = "CURRENT_STATE";
+ private static final String TOSYNC_STATE = "TOSYNC_STATE";
+ private static final String SESSION = "session";
+ private static final String ID = "id";
+ private static final String ERRORS = "errors";
+
+ protected static final String IDENTIFIER = "identifier";
+ protected static final String DEVICE_TYPE = "device_type";
+ protected static final String DEVICE_PLAYER_ID = "device_player_id";
+ protected static final String PARENT_PLAYER_ID = "parent_player_id";
+ protected static final String USER_SUBSCRIBE_PREF = "userSubscribePref";
+ protected static final String ANDROID_PERMISSION = "androidPermission";
+ protected static final String SUBSCRIBABLE_STATUS = "subscribableStatus";
+ protected static final String TAGS = "tags";
+ protected static final String EXTERNAL_USER_ID = "external_user_id";
+ protected static final String EMAIL_KEY = "email";
+ protected static final String LOGOUT_EMAIL = "logoutEmail";
+ protected static final String SMS_NUMBER_KEY = "sms_number";
+
+ static final String EXTERNAL_USER_ID_AUTH_HASH = "external_user_id_auth_hash";
+ static final String EMAIL_AUTH_HASH_KEY = "email_auth_hash";
+ static final String SMS_AUTH_HASH_KEY = "sms_auth_hash";
+ static final String APP_ID = "app_id";
+
// Object to synchronize on to prevent concurrent modifications on syncValues and dependValues
protected final Object LOCK = new Object();
@@ -50,10 +75,11 @@ static class GetTagsResult {
}
}
+ abstract void saveChannelId(String id);
abstract boolean getSubscribed();
String getRegistrationId() {
- return getToSyncUserState().getSyncValues().optString("identifier", null);
+ return getToSyncUserState().getSyncValues().optString(IDENTIFIER, null);
}
abstract GetTagsResult getTags(boolean fromServer);
@@ -72,6 +98,7 @@ boolean hasQueuedHandlers() {
}
class NetworkHandlerThread extends HandlerThread {
+ private static final String THREAD_NAME_PREFIX = "OSH_NetworkHandlerThread_";
protected static final int NETWORK_HANDLER_USERSTATE = 0;
int mType;
@@ -82,7 +109,7 @@ class NetworkHandlerThread extends HandlerThread {
int currentRetry;
NetworkHandlerThread(int type) {
- super("OSH_NetworkHandlerThread");
+ super(THREAD_NAME_PREFIX + UserStateSynchronizer.this.channel);
mType = type;
start();
mHandler = new Handler(getLooper());
@@ -156,7 +183,7 @@ protected UserState getCurrentUserState() {
if (currentUserState == null) {
synchronized (LOCK) {
if (currentUserState == null)
- currentUserState = newUserState("CURRENT_STATE", true);
+ currentUserState = newUserState(CURRENT_STATE, true);
}
}
@@ -167,7 +194,7 @@ protected UserState getToSyncUserState() {
if (toSyncUserState == null) {
synchronized (LOCK) {
if (toSyncUserState == null)
- toSyncUserState = newUserState("TOSYNC_STATE", true);
+ toSyncUserState = newUserState(TOSYNC_STATE, true);
}
}
@@ -178,7 +205,7 @@ void initUserState() {
if (currentUserState == null) {
synchronized (LOCK) {
if (currentUserState == null)
- currentUserState = newUserState("CURRENT_STATE", true);
+ currentUserState = newUserState(CURRENT_STATE, true);
}
}
getToSyncUserState();
@@ -206,12 +233,12 @@ boolean persist() {
protected abstract String getId();
private boolean isSessionCall() {
- boolean toSyncSession = getToSyncUserState().getDependValues().optBoolean("session");
+ boolean toSyncSession = getToSyncUserState().getDependValues().optBoolean(SESSION);
return (toSyncSession || getId() == null) && !waitingForSessionResponse;
}
private boolean syncEmailLogout() {
- return getToSyncUserState().getDependValues().optBoolean("logoutEmail", false);
+ return getToSyncUserState().getDependValues().optBoolean(LOGOUT_EMAIL, false);
}
void syncUserState(boolean fromSyncService) {
@@ -259,14 +286,14 @@ private void doEmailLogout(String userId) {
JSONObject jsonBody = new JSONObject();
try {
ImmutableJSONObject dependValues = currentUserState.getDependValues();
- if (dependValues.has("email_auth_hash"))
- jsonBody.put("email_auth_hash", dependValues.optString("email_auth_hash"));
+ if (dependValues.has(EMAIL_AUTH_HASH_KEY))
+ jsonBody.put(EMAIL_AUTH_HASH_KEY, dependValues.optString(EMAIL_AUTH_HASH_KEY));
ImmutableJSONObject syncValues = currentUserState.getSyncValues();
- if (syncValues.has("parent_player_id"))
- jsonBody.put("parent_player_id", syncValues.optString("parent_player_id"));
+ if (syncValues.has(PARENT_PLAYER_ID))
+ jsonBody.put(PARENT_PLAYER_ID, syncValues.optString(PARENT_PLAYER_ID));
- jsonBody.put("app_id", syncValues.optString("app_id"));
+ jsonBody.put(APP_ID, syncValues.optString(APP_ID));
} catch (JSONException e) {
e.printStackTrace();
}
@@ -295,16 +322,16 @@ void onSuccess(String response) {
}
private void logoutEmailSyncSuccess() {
- getToSyncUserState().removeFromDependValues("logoutEmail");
- toSyncUserState.removeFromDependValues("email_auth_hash");
- toSyncUserState.removeFromSyncValues("parent_player_id");
- toSyncUserState.removeFromSyncValues("email");
+ getToSyncUserState().removeFromDependValues(LOGOUT_EMAIL);
+ toSyncUserState.removeFromDependValues(EMAIL_AUTH_HASH_KEY);
+ toSyncUserState.removeFromSyncValues(PARENT_PLAYER_ID);
+ toSyncUserState.removeFromSyncValues(EMAIL_KEY);
toSyncUserState.persistState();
- currentUserState.removeFromDependValues("email_auth_hash");
- currentUserState.removeFromSyncValues("parent_player_id");
- String emailLoggedOut = currentUserState.getSyncValues().optString("email");
- currentUserState.removeFromSyncValues("email");
+ currentUserState.removeFromDependValues(EMAIL_AUTH_HASH_KEY);
+ currentUserState.removeFromSyncValues(PARENT_PLAYER_ID);
+ String emailLoggedOut = currentUserState.getSyncValues().optString(EMAIL_KEY);
+ currentUserState.removeFromSyncValues(EMAIL_KEY);
OneSignalStateSynchronizer.setNewSessionForEmail();
@@ -332,10 +359,10 @@ void onFailure(int statusCode, String response, Throwable throwable) {
handleNetworkFailure(statusCode);
}
- if (jsonBody.has("tags"))
+ if (jsonBody.has(TAGS))
sendTagsHandlersPerformOnFailure(new SendTagsError(statusCode, response));
- if (jsonBody.has("external_user_id")) {
+ if (jsonBody.has(EXTERNAL_USER_ID)) {
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "Error setting external user id for push with status code: " + statusCode + " and message: " + response);
externalUserIdUpdateHandlersPerformOnFailure();
}
@@ -348,10 +375,10 @@ void onSuccess(String response) {
onSuccessfulSync(jsonBody);
}
- if (jsonBody.has("tags"))
+ if (jsonBody.has(TAGS))
sendTagsHandlersPerformOnSuccess();
- if (jsonBody.has("external_user_id"))
+ if (jsonBody.has(EXTERNAL_USER_ID))
externalUserIdUpdateHandlersPerformOnSuccess();
}
});
@@ -390,15 +417,15 @@ void onSuccess(String response) {
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "doCreateOrNewSession:response: " + response);
JSONObject jsonResponse = new JSONObject(response);
- if (jsonResponse.has("id")) {
- String newUserId = jsonResponse.optString("id");
+ if (jsonResponse.has(ID)) {
+ String newUserId = jsonResponse.optString(ID);
updateIdDependents(newUserId);
OneSignal.Log(OneSignal.LOG_LEVEL.INFO, "Device registered, UserId = " + newUserId);
}
else
OneSignal.Log(OneSignal.LOG_LEVEL.INFO, "session sent, UserId = " + userId);
- getUserStateForModification().putOnDependValues("session", false);
+ getUserStateForModification().putOnDependValues(SESSION, false);
getUserStateForModification().persistState();
// List of in app messages to evaluate for the session
@@ -434,7 +461,7 @@ private void fireNetworkFailureEvents() {
if (jsonBody != null)
fireEventsForUpdateFailure(jsonBody);
- if (getToSyncUserState().getDependValues().optBoolean("logoutEmail", false))
+ if (getToSyncUserState().getDependValues().optBoolean(LOGOUT_EMAIL, false))
OneSignal.handleFailedEmailLogout();
}
@@ -446,7 +473,7 @@ private boolean response400WithErrorsContaining(int statusCode, String response,
if (statusCode == 400 && response != null) {
try {
JSONObject responseJson = new JSONObject(response);
- return responseJson.has("errors") && responseJson.optString("errors").contains(contains);
+ return responseJson.has(ERRORS) && responseJson.optString(ERRORS).contains(contains);
} catch (JSONException e) {
e.printStackTrace();
}
@@ -468,7 +495,7 @@ protected NetworkHandlerThread getNetworkHandlerThread(Integer type) {
// If there are differences a network call with the changes to made
protected UserState getUserStateForModification() {
if (toSyncUserState == null)
- toSyncUserState = getCurrentUserState().deepClone("TOSYNC_STATE");
+ toSyncUserState = getCurrentUserState().deepClone(TOSYNC_STATE);
scheduleSyncToServer();
@@ -486,7 +513,7 @@ void updateDeviceInfo(JSONObject deviceInfo) {
void setNewSession() {
try {
synchronized (LOCK) {
- getUserStateForModification().putOnDependValues("session", true);
+ getUserStateForModification().putOnDependValues(SESSION, true);
getUserStateForModification().persistState();
}
} catch (JSONException e) {
@@ -495,7 +522,7 @@ void setNewSession() {
}
boolean getSyncAsNewSession() {
- return getUserStateForModification().getDependValues().optBoolean("session");
+ return getUserStateForModification().getDependValues().optBoolean(SESSION);
}
void sendTags(JSONObject tags, @Nullable ChangeTagsUpdateHandler handler) {
@@ -514,9 +541,9 @@ void setExternalUserId(final String externalId, final String externalIdAuthHash,
this.externalUserIdUpdateHandlers.add(handler);
UserState userState = getUserStateForModification();
- userState.putOnSyncValues("external_user_id", externalId);
+ userState.putOnSyncValues(EXTERNAL_USER_ID, externalId);
if (externalIdAuthHash != null)
- userState.putOnSyncValues("external_user_id_auth_hash", externalIdAuthHash);
+ userState.putOnSyncValues(EXTERNAL_USER_ID_AUTH_HASH, externalIdAuthHash);
}
abstract void setSubscription(boolean enable);
@@ -544,7 +571,11 @@ void updateLocation(LocationController.LocationPoint point) {
abstract void updateIdDependents(String id);
- abstract void logoutEmail();
+ abstract void logoutChannel();
+
+ void sendPurchases(JSONObject jsonBody, OneSignalRestClient.ResponseHandler responseHandler) {
+ OneSignalRestClient.post("players/" + getId() + "/on_purchase", jsonBody, responseHandler);
+ }
void readyToUpdate(boolean canMakeUpdates) {
boolean changed = this.canMakeUpdates != canMakeUpdates;
diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java
index d8ecdf2b97..3929c43687 100644
--- a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java
+++ b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java
@@ -44,6 +44,10 @@ private static void processNetworkHandles(RunnableArg runnable) throws Exception
entrySet = OneSignalStateSynchronizer.getEmailStateSynchronizer().networkHandlerThreads.entrySet();
for (Map.Entry handlerThread : entrySet)
runnable.run(handlerThread.getValue());
+
+ entrySet = OneSignalStateSynchronizer.getSMSStateSynchronizer().networkHandlerThreads.entrySet();
+ for (Map.Entry handlerThread : entrySet)
+ runnable.run(handlerThread.getValue());
}
private static boolean startedRunnable;
diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java
index 6f4fdd874d..6a5403d39a 100644
--- a/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java
+++ b/OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowOneSignalRestClient.java
@@ -39,9 +39,15 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
+import static com.onesignal.UserState.DEVICE_TYPE_EMAIL;
+import static com.onesignal.UserState.DEVICE_TYPE_SMS;
+
@Implements(OneSignalRestClient.class)
public class ShadowOneSignalRestClient {
+ public static final String PUSH_USER_ID = "a2f7f967-e8cc-11e4-bed1-118f05be4511";
+ public static final String EMAIL_USER_ID = "b007f967-98cc-11e4-bed1-118f05be4522";
+ public static final String SMS_USER_ID = "d007f967-98cc-11e4-bed1-118f05be4522";
public enum REST_METHOD {
GET, POST, PUT
}
@@ -86,7 +92,7 @@ private static class PendingResponse {
public static List successfulGETResponses = new ArrayList<>();
public static ArrayList requests;
- public static String lastUrl, failResponse, nextSuccessResponse, nextSuccessfulGETResponse, nextSuccessfulRegistrationResponse, pushUserId, emailUserId, failMethod;
+ public static String lastUrl, failResponse, nextSuccessResponse, nextSuccessfulGETResponse, nextSuccessfulRegistrationResponse, pushUserId, emailUserId, smsUserId, failMethod;
public static Pattern nextSuccessfulGETResponsePattern;
public static JSONObject lastPost;
public static boolean failNext, failNextPut, failAll, failPosts, failGetParams;
@@ -134,8 +140,9 @@ private static class PendingResponse {
}
public static void resetStatics() {
- pushUserId = "a2f7f967-e8cc-11e4-bed1-118f05be4511";
- emailUserId = "b007f967-98cc-11e4-bed1-118f05be4522";
+ pushUserId = PUSH_USER_ID;
+ emailUserId = EMAIL_USER_ID;
+ smsUserId = SMS_USER_ID;
requests = new ArrayList<>();
lastPost = null;
@@ -304,7 +311,17 @@ else if (url.contains("on_session"))
retJson = "{}";
else {
int device_type = jsonBody.optInt("device_type", 0);
- String id = device_type == 11 ? emailUserId : pushUserId;
+ String id;
+ switch (device_type) {
+ case DEVICE_TYPE_EMAIL:
+ id = emailUserId;
+ break;
+ case DEVICE_TYPE_SMS:
+ id = smsUserId;
+ break;
+ default:
+ id = pushUserId;
+ }
retJson = "{\"id\": \"" + id + "\"}";
}
diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java
index cb441438e1..34fb3387fd 100644
--- a/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java
+++ b/OneSignalSDK/unittest/src/test/java/com/onesignal/StaticResetHelper.java
@@ -2,8 +2,6 @@
package com.onesignal;
-import android.util.Log;
-
import org.json.JSONArray;
import java.lang.reflect.Field;
@@ -13,7 +11,6 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
public class StaticResetHelper {
diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java
new file mode 100644
index 0000000000..fe44cc9153
--- /dev/null
+++ b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/LocationIntegrationTests.java
@@ -0,0 +1,614 @@
+package com.test.onesignal;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.huawei.hms.location.HWLocation;
+import com.onesignal.FocusDelaySyncService;
+import com.onesignal.MockOSLog;
+import com.onesignal.MockOSSharedPreferences;
+import com.onesignal.MockOSTimeImpl;
+import com.onesignal.MockOneSignalDBHelper;
+import com.onesignal.MockSessionManager;
+import com.onesignal.OneSignal;
+import com.onesignal.OneSignalPackagePrivateHelper;
+import com.onesignal.ShadowAdvertisingIdProviderGPS;
+import com.onesignal.ShadowCustomTabsClient;
+import com.onesignal.ShadowCustomTabsSession;
+import com.onesignal.ShadowFusedLocationApiWrapper;
+import com.onesignal.ShadowGMSLocationController;
+import com.onesignal.ShadowGMSLocationUpdateListener;
+import com.onesignal.ShadowGoogleApiClientBuilder;
+import com.onesignal.ShadowGoogleApiClientCompatProxy;
+import com.onesignal.ShadowHMSFusedLocationProviderClient;
+import com.onesignal.ShadowHMSLocationUpdateListener;
+import com.onesignal.ShadowHmsInstanceId;
+import com.onesignal.ShadowHuaweiTask;
+import com.onesignal.ShadowOSUtils;
+import com.onesignal.ShadowOneSignal;
+import com.onesignal.ShadowOneSignalRestClient;
+import com.onesignal.ShadowPushRegistratorFCM;
+import com.onesignal.StaticResetHelper;
+import com.onesignal.SyncJobService;
+import com.onesignal.SyncService;
+import com.onesignal.example.BlankActivity;
+import com.onesignal.influence.data.OSTrackerFactory;
+
+import org.json.JSONObject;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowLog;
+
+import java.lang.reflect.Method;
+
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory;
+import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse;
+import static com.test.onesignal.TestHelpers.afterTestCleanup;
+import static com.test.onesignal.TestHelpers.fastColdRestartApp;
+import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession;
+import static com.test.onesignal.TestHelpers.threadAndTaskWait;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static org.robolectric.Shadows.shadowOf;
+
+@Config(packageName = "com.onesignal.example",
+ shadows = {
+ ShadowOneSignalRestClient.class,
+ ShadowPushRegistratorFCM.class,
+ ShadowOSUtils.class,
+ ShadowAdvertisingIdProviderGPS.class,
+ ShadowCustomTabsClient.class,
+ ShadowCustomTabsSession.class,
+ ShadowHmsInstanceId.class,
+ },
+ sdk = 21
+)
+@RunWith(RobolectricTestRunner.class)
+public class LocationIntegrationTests {
+
+ private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba";
+
+ @SuppressLint("StaticFieldLeak")
+ private static Activity blankActivity;
+ private static ActivityController blankActivityController;
+
+ private MockOSTimeImpl time;
+ private OSTrackerFactory trackerFactory;
+ private MockSessionManager sessionManager;
+ private MockOneSignalDBHelper dbHelper;
+
+ private static void cleanUp() throws Exception {
+ ShadowGMSLocationController.reset();
+
+ TestHelpers.beforeTestInitAndCleanup();
+
+ // Set remote_params GET response
+ setRemoteParamsGetHtmlResponse();
+ }
+
+ @BeforeClass // Runs only once, before any tests
+ public static void setUpClass() throws Exception {
+ ShadowLog.stream = System.out;
+
+ TestHelpers.beforeTestSuite();
+
+// Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus");
+// OneSignal_CurrentSubscription.setAccessible(true);
+
+ OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
+ StaticResetHelper.saveStaticValues();
+ }
+
+ @Before
+ public void beforeEachTest() throws Exception {
+ blankActivityController = Robolectric.buildActivity(BlankActivity.class).create();
+ blankActivity = blankActivityController.get();
+
+ time = new MockOSTimeImpl();
+ trackerFactory = new OSTrackerFactory(new MockOSSharedPreferences(), new MockOSLog(), time);
+ sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog());
+ dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext());
+
+ TestHelpers.setupTestWorkManager(blankActivity);
+
+ cleanUp();
+
+ OneSignal_setTime(time);
+ }
+
+ @After
+ public void afterEachTest() throws Exception {
+ afterTestCleanup();
+ }
+
+ @AfterClass
+ public static void afterEverything() throws Exception {
+ cleanUp();
+ }
+
+ @Test
+ @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
+ public void shouldUpdateAllLocationFieldsWhenTimeStampChanges() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+ OneSignalInit();
+ threadAndTaskWait();
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
+ assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
+
+ ShadowOneSignalRestClient.lastPost = null;
+ ShadowFusedLocationApiWrapper.lat = 30d;
+ ShadowFusedLocationApiWrapper.log = 2.0d;
+ ShadowFusedLocationApiWrapper.accuracy = 5.0f;
+ ShadowFusedLocationApiWrapper.time = 2L;
+ restartAppAndElapseTimeToNextSession(time);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
+ assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
+ assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowOneSignal.class})
+ @SuppressWarnings("unchecked") // getDeclaredMethod
+ public void testLocationTimeout() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ Class klass = Class.forName("com.onesignal.GMSLocationController");
+ Method method = klass.getDeclaredMethod("startFallBackThread");
+ method.setAccessible(true);
+ method.invoke(null);
+ method = klass.getDeclaredMethod("fireFailedComplete");
+ method.setAccessible(true);
+ method.invoke(null);
+ threadAndTaskWait();
+
+ assertFalse(ShadowOneSignal.messages.contains("GoogleApiClient timeout"));
+ }
+
+ @Test
+ @Config(shadows = {
+ ShadowGoogleApiClientBuilder.class,
+ ShadowGoogleApiClientCompatProxy.class,
+ ShadowFusedLocationApiWrapper.class },
+ sdk = 19)
+ public void testLocationSchedule() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_FINE_LOCATION");
+ ShadowFusedLocationApiWrapper.lat = 1.0d;
+ ShadowFusedLocationApiWrapper.log = 2.0d;
+ ShadowFusedLocationApiWrapper.accuracy = 3.0f;
+ ShadowFusedLocationApiWrapper.time = 12345L;
+
+ // location if we have permission
+ OneSignalInit();
+ threadAndTaskWait();
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
+ assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+
+ // Checking make sure an update is scheduled.
+ AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
+ Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
+ assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
+
+ // Setting up a new point and testing it is sent
+ Location fakeLocation = new Location("UnitTest");
+ fakeLocation.setLatitude(1.1d);
+ fakeLocation.setLongitude(2.2d);
+ fakeLocation.setAccuracy(3.3f);
+ fakeLocation.setTime(12346L);
+ ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation);
+
+ Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+ assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
+
+ assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+ assertEquals("11111111-2222-3333-4444-555555555555", ShadowOneSignalRestClient.lastPost.opt("ad_id"));
+
+ // Testing loc_bg
+ blankActivityController.pause();
+ threadAndTaskWait();
+ Robolectric.buildService(FocusDelaySyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+ fakeLocation.setTime(12347L);
+ ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation);
+ Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+ assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
+ assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+ assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+ assertEquals("11111111-2222-3333-4444-555555555555", ShadowOneSignalRestClient.lastPost.opt("ad_id"));
+ }
+
+ @Test
+ @Config(shadows = {
+ ShadowGoogleApiClientBuilder.class,
+ ShadowGoogleApiClientCompatProxy.class,
+ ShadowFusedLocationApiWrapper.class },
+ sdk = 19)
+ public void testLocationFromSyncAlarm() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ ShadowFusedLocationApiWrapper.lat = 1.1d;
+ ShadowFusedLocationApiWrapper.log = 2.1d;
+ ShadowFusedLocationApiWrapper.accuracy = 3.1f;
+ ShadowFusedLocationApiWrapper.time = 12346L;
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ fastColdRestartApp();
+ AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ shadowOf(alarmManager).getScheduledAlarms().clear();
+ ShadowOneSignalRestClient.lastPost = null;
+
+ ShadowFusedLocationApiWrapper.lat = 1.0;
+ ShadowFusedLocationApiWrapper.log = 2.0d;
+ ShadowFusedLocationApiWrapper.accuracy = 3.0f;
+ ShadowFusedLocationApiWrapper.time = 12345L;
+
+ blankActivityController.pause();
+ threadAndTaskWait();
+ Robolectric.buildService(FocusDelaySyncService.class, new Intent()).startCommand(0, 0);
+ threadAndTaskWait();
+ Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0);
+ threadAndTaskWait();
+
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
+ assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+ assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp"));
+ assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+
+ // Checking make sure an update is scheduled.
+ alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
+ Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
+ assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
+ shadowOf(alarmManager).getScheduledAlarms().clear();
+ }
+
+ @Test
+ @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
+ public void shouldSendLocationToEmailRecord() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(11, postEmailPayload.getInt("device_type"));
+ assertEquals(1.0, postEmailPayload.getDouble("lat"));
+ assertEquals(2.0, postEmailPayload.getDouble("long"));
+ assertEquals(3.0, postEmailPayload.getDouble("loc_acc"));
+ assertEquals(0.0, postEmailPayload.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
+ public void shouldSendLocationToSMSRecord() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ OneSignal.setSMSNumber("123456789");
+ threadAndTaskWait();
+
+ JSONObject postSMSPayload = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, postSMSPayload.getInt("device_type"));
+ assertEquals(1.0, postSMSPayload.getDouble("lat"));
+ assertEquals(2.0, postSMSPayload.getDouble("long"));
+ assertEquals(3.0, postSMSPayload.getDouble("loc_acc"));
+ assertEquals(0.0, postSMSPayload.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
+ public void shouldRegisterWhenPromptingAfterInit() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+ ShadowGoogleApiClientCompatProxy.skipOnConnected = true;
+
+ // Test promptLocation right after init race condition
+ OneSignalInit();
+ OneSignal.promptLocation();
+
+ ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method);
+ assertEquals(1, request.payload.get("device_type"));
+ assertEquals(ShadowPushRegistratorFCM.regId, request.payload.get("identifier"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
+ public void shouldCallOnSessionEvenIfSyncJobStarted() throws Exception {
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ restartAppAndElapseTimeToNextSession(time);
+ ShadowGoogleApiClientCompatProxy.skipOnConnected = true;
+ OneSignalInit();
+
+ SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get();
+ syncJobService.onStartJob(null);
+ TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join();
+ OneSignalPackagePrivateHelper.runAllNetworkRunnables();
+ ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url);
+ }
+
+ // ####### Unit Test Huawei Location ########
+
+ @Test
+ @Config(shadows = {ShadowHMSFusedLocationProviderClient.class})
+ public void shouldUpdateAllLocationFieldsWhenTimeStampChanges_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+ OneSignalInit();
+ threadAndTaskWait();
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
+ assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
+
+ ShadowOneSignalRestClient.lastPost = null;
+ ShadowHMSFusedLocationProviderClient.resetStatics();
+ ShadowHMSFusedLocationProviderClient.lat = 30d;
+ ShadowHMSFusedLocationProviderClient.log = 2.0d;
+ ShadowHMSFusedLocationProviderClient.accuracy = 5.0f;
+ ShadowHMSFusedLocationProviderClient.time = 2L;
+ restartAppAndElapseTimeToNextSession(time);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
+ assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
+ assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {
+ ShadowHMSFusedLocationProviderClient.class
+ }, sdk = 19)
+ public void testLocationSchedule_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_FINE_LOCATION");
+ ShadowHMSFusedLocationProviderClient.lat = 1.0d;
+ ShadowHMSFusedLocationProviderClient.log = 2.0d;
+ ShadowHMSFusedLocationProviderClient.accuracy = 3.0f;
+ ShadowHMSFusedLocationProviderClient.time = 12345L;
+
+ // location if we have permission
+ OneSignalInit();
+ threadAndTaskWait();
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
+ assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+
+ // Checking make sure an update is scheduled.
+ AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
+ Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
+ assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
+
+ // Setting up a new point and testing it is sent
+ HWLocation fakeLocation = new HWLocation();
+ fakeLocation.setLatitude(1.1d);
+ fakeLocation.setLongitude(2.2d);
+ fakeLocation.setAccuracy(3.3f);
+ fakeLocation.setTime(12346L);
+ ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation);
+
+ Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+ assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
+
+ assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+ // Currently not getting ad_id for HMS devices
+ assertNull(ShadowOneSignalRestClient.lastPost.opt("ad_id"));
+
+ // Testing loc_bg
+ blankActivityController.pause();
+ threadAndTaskWait();
+ Robolectric.buildService(FocusDelaySyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+
+ fakeLocation.setTime(12347L);
+ ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation);
+ Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
+ threadAndTaskWait();
+ assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
+ assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+ assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+ // Currently not getting ad_id for HMS devices
+ assertNull(ShadowOneSignalRestClient.lastPost.opt("ad_id"));
+ }
+
+ @Test
+ @Config(shadows = {
+ ShadowHMSFusedLocationProviderClient.class,
+ ShadowHuaweiTask.class
+ }, sdk = 19)
+ public void testLocationFromSyncAlarm_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ ShadowHMSFusedLocationProviderClient.lat = 1.1d;
+ ShadowHMSFusedLocationProviderClient.log = 2.1d;
+ ShadowHMSFusedLocationProviderClient.accuracy = 3.1f;
+ ShadowHMSFusedLocationProviderClient.time = 12346L;
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ fastColdRestartApp();
+ AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ shadowOf(alarmManager).getScheduledAlarms().clear();
+
+ ShadowOneSignalRestClient.lastPost = null;
+ ShadowHMSFusedLocationProviderClient.resetStatics();
+ ShadowHMSFusedLocationProviderClient.lat = 1.0;
+ ShadowHMSFusedLocationProviderClient.log = 2.0d;
+ ShadowHMSFusedLocationProviderClient.accuracy = 3.0f;
+ ShadowHMSFusedLocationProviderClient.time = 12345L;
+ ShadowHMSFusedLocationProviderClient.shadowTask = true;
+ ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation();
+
+ Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0);
+ threadAndTaskWait();
+
+ assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
+ assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
+ assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
+ assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
+ assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp"));
+ assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
+
+ // Checking make sure an update is scheduled.
+ alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
+ Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
+ assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
+ shadowOf(alarmManager).getScheduledAlarms().clear();
+ }
+
+ @Test
+ @Config(shadows = {ShadowHMSFusedLocationProviderClient.class})
+ public void shouldSendLocationToEmailRecord_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(11, postEmailPayload.getInt("device_type"));
+ assertEquals(1.0, postEmailPayload.getDouble("lat"));
+ assertEquals(2.0, postEmailPayload.getDouble("long"));
+ assertEquals(3.0, postEmailPayload.getDouble("loc_acc"));
+ assertEquals(0.0, postEmailPayload.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowHMSFusedLocationProviderClient.class})
+ public void shouldSendLocationToSMSRecord_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ OneSignal.setSMSNumber("123456789");
+ threadAndTaskWait();
+
+ JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, postEmailPayload.getInt("device_type"));
+ assertEquals(1.0, postEmailPayload.getDouble("lat"));
+ assertEquals(2.0, postEmailPayload.getDouble("long"));
+ assertEquals(3.0, postEmailPayload.getDouble("loc_acc"));
+ assertEquals(0.0, postEmailPayload.getDouble("loc_type"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class})
+ public void shouldRegisterWhenPromptingAfterInit_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true;
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ // Test promptLocation right after init race condition
+ OneSignalInit();
+ OneSignal.promptLocation();
+
+ ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation());
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method);
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_HUAWEI, request.payload.get("device_type"));
+ assertEquals(ShadowHmsInstanceId.token, request.payload.get("identifier"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class})
+ public void shouldCallOnSessionEvenIfSyncJobStarted_Huawei() throws Exception {
+ ShadowOSUtils.supportsHMS(true);
+ ShadowHMSFusedLocationProviderClient.shadowTask = true;
+ ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation();
+ ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ restartAppAndElapseTimeToNextSession(time);
+ ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true;
+ OneSignalInit();
+
+ SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get();
+ syncJobService.onStartJob(null);
+ TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join();
+ OneSignalPackagePrivateHelper.runAllNetworkRunnables();
+ ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation());
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, request.method);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url);
+ }
+
+ private void OneSignalInit() {
+ OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
+ ShadowOSUtils.subscribableStatus = 1;
+ OneSignal_setTime(time);
+ OneSignal_setTrackerFactory(trackerFactory);
+ OneSignal_setSessionManager(sessionManager);
+ OneSignal.setAppId(ONESIGNAL_APP_ID);
+ OneSignal.initWithContext(blankActivity);
+ blankActivityController.resume();
+ }
+}
diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java
index 0c367af6dd..15abd1b943 100644
--- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java
+++ b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java
@@ -36,13 +36,11 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
-import android.location.Location;
import android.net.ConnectivityManager;
import android.os.Bundle;
import androidx.test.core.app.ApplicationProvider;
-import com.huawei.hms.location.HWLocation;
import com.onesignal.FocusDelaySyncJobService;
import com.onesignal.FocusDelaySyncService;
import com.onesignal.MockOSLog;
@@ -59,12 +57,13 @@
import com.onesignal.OSNotificationReceivedEvent;
import com.onesignal.OSPermissionObserver;
import com.onesignal.OSPermissionStateChanges;
+import com.onesignal.OSSMSSubscriptionObserver;
+import com.onesignal.OSSMSSubscriptionStateChanges;
import com.onesignal.OSSubscriptionObserver;
import com.onesignal.OSSubscriptionStateChanges;
import com.onesignal.OneSignal;
import com.onesignal.OneSignal.ChangeTagsUpdateHandler;
import com.onesignal.OneSignalPackagePrivateHelper;
-import com.onesignal.OneSignalPackagePrivateHelper.UserState;
import com.onesignal.OneSignalShadowPackageManager;
import com.onesignal.PermissionsActivity;
import com.onesignal.ShadowAdvertisingIdProviderGPS;
@@ -74,14 +73,10 @@
import com.onesignal.ShadowFirebaseAnalytics;
import com.onesignal.ShadowFusedLocationApiWrapper;
import com.onesignal.ShadowGMSLocationController;
-import com.onesignal.ShadowGMSLocationUpdateListener;
import com.onesignal.ShadowGenerateNotification;
import com.onesignal.ShadowGoogleApiClientBuilder;
import com.onesignal.ShadowGoogleApiClientCompatProxy;
-import com.onesignal.ShadowHMSFusedLocationProviderClient;
-import com.onesignal.ShadowHMSLocationUpdateListener;
import com.onesignal.ShadowHmsInstanceId;
-import com.onesignal.ShadowHuaweiTask;
import com.onesignal.ShadowJobService;
import com.onesignal.ShadowNotificationManagerCompat;
import com.onesignal.ShadowOSUtils;
@@ -116,7 +111,6 @@
import org.robolectric.shadows.ShadowLog;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -128,7 +122,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
-import static com.onesignal.OneSignal.ExternalIdErrorType.REQUIRES_EXTERNAL_ID_AUTH;
import static com.onesignal.OneSignalPackagePrivateHelper.FCMBroadcastReceiver_processBundle;
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_Process;
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationOpenedProcessor_processFromContext;
@@ -139,7 +132,10 @@
import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime;
import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory;
import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_taskQueueWaitingForInit;
+import static com.onesignal.ShadowOneSignalRestClient.EMAIL_USER_ID;
+import static com.onesignal.ShadowOneSignalRestClient.PUSH_USER_ID;
import static com.onesignal.ShadowOneSignalRestClient.REST_METHOD;
+import static com.onesignal.ShadowOneSignalRestClient.SMS_USER_ID;
import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse;
import static com.test.onesignal.GenerateNotificationRunner.getBaseNotifBundle;
import static com.test.onesignal.RestClientAsserts.assertAmazonPlayerCreateAtIndex;
@@ -195,6 +191,7 @@ public class MainOneSignalClassRunner {
private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba";
private static final String ONESIGNAL_NOTIFICATION_ID = "97d8e764-81c2-49b0-a644-713d052ae7d5";
+ private static final String ONESIGNAL_SMS_NUMBER = "123456789";
private static final String TIMEZONE_ID = "Europe/London";
@SuppressLint("StaticFieldLeak")
@@ -216,50 +213,19 @@ private static OneSignal.OSNotificationOpenedHandler getNotificationOpenedHandle
};
}
- private static JSONObject lastExternalUserIdResponse;
- private static OneSignal.ExternalIdError lastExternalUserIdError;
- private static OneSignal.OSExternalUserIdUpdateCompletionHandler getExternalUserIdUpdateCompletionHandler() {
- return new OneSignal.OSExternalUserIdUpdateCompletionHandler() {
- @Override
- public void onSuccess(JSONObject results) {
- lastExternalUserIdResponse = results;
- }
-
- @Override
- public void onFailure(OneSignal.ExternalIdError error) {
- lastExternalUserIdError = error;
- }
- };
- }
-
- private static boolean didEmailUpdateSucceed;
- private static OneSignal.EmailUpdateError lastEmailUpdateFailure;
- private static OneSignal.EmailUpdateHandler getEmailUpdateHandler() {
- return new OneSignal.EmailUpdateHandler() {
- @Override
- public void onSuccess() {
- didEmailUpdateSucceed = true;
- }
-
- @Override
- public void onFailure(OneSignal.EmailUpdateError error) {
- lastEmailUpdateFailure = error;
- }
- };
- }
-
private static JSONObject lastGetTags;
private static void getGetTagsHandler() {
OneSignal.getTags(tags -> lastGetTags = tags);
}
+ private static OSEmailSubscriptionStateChanges lastEmailSubscriptionStateChanges;
+ private static OSSMSSubscriptionStateChanges lastSMSSubscriptionStateChanges;
+
private static void cleanUp() throws Exception {
lastNotificationOpenedBody = null;
lastGetTags = null;
- lastExternalUserIdResponse = null;
- lastExternalUserIdError = null;
- lastEmailUpdateFailure = null;
- didEmailUpdateSucceed = false;
+ lastEmailSubscriptionStateChanges = null;
+ lastSMSSubscriptionStateChanges = null;
ShadowGMSLocationController.reset();
@@ -1420,7 +1386,6 @@ public void shouldUpdateNotificationTypesCorrectlyEvenWhenSetSubscriptionIsCalle
assertEquals(1, ShadowOneSignalRestClient.lastPost.getInt("notification_types"));
}
-
@Test
public void shouldAllowMultipleSetSubscription() throws Exception {
OneSignalInit();
@@ -1436,8 +1401,6 @@ public void shouldAllowMultipleSetSubscription() throws Exception {
OneSignal.disablePush(true);
assertNull(ShadowOneSignalRestClient.lastPost);
-
-
OneSignal.disablePush(false);
threadAndTaskWait();
assertEquals(1, ShadowOneSignalRestClient.lastPost.getInt("notification_types"));
@@ -1634,349 +1597,6 @@ public void remoteNotificationReceived(Context context, OSNotificationReceivedEv
}
}
- @Test
- public void shouldSetEmail() throws Exception {
- OneSignalInit();
- String email = "josh@onesignal.com";
-
- OneSignal.setEmail(email);
- threadAndTaskWait();
-
- assertEquals(4, ShadowOneSignalRestClient.networkCallCount);
-
- JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload;
- assertEquals(email, pushPost.getString("email"));
- assertEquals(1, pushPost.getInt("device_type"));
-
- JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
- assertEquals(email, emailPost.getString("identifier"));
- assertEquals(11, emailPost.getInt("device_type"));
- assertEquals(ShadowOneSignalRestClient.pushUserId, emailPost.getString("device_player_id"));
-
- JSONObject pushPut = ShadowOneSignalRestClient.requests.get(3).payload;
- assertEquals(ShadowOneSignalRestClient.emailUserId, pushPut.getString("parent_player_id"));
- assertFalse(pushPut.has("identifier"));
- }
-
- @Test
- public void shouldSendTagsToEmailBeforeCreate() throws Exception {
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
- OneSignal.sendTags(tagsJson);
- threadAndTaskWait();
-
- assertEquals(4, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals("josh@onesignal.com", emailPost.payload.get("identifier"));
- assertEquals(tagsJson.toString(), emailPost.payload.getJSONObject("tags").toString());
- }
-
- @Test
- public void shouldWaitBeforeCreateEmailIfPushCreateFails() throws Exception {
- ShadowOneSignalRestClient.failPosts = true;
-
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- // Assert we are sending / retry for the push player first.
- assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
- for(int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) {
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(i);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals(1, emailPost.payload.getInt("device_type"));
- }
-
- // Turn off fail mocking, call sendTags to trigger another retry
- ShadowOneSignalRestClient.failPosts = false;
- OneSignal.sendTag("test", "test");
- threadAndTaskWait();
-
- // Should now POST to create device_type 11 (email)
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals("josh@onesignal.com", emailPost.payload.get("identifier"));
- }
-
- @Test
- public void shouldSendTagsToEmailAfterCreate() throws Exception {
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
- OneSignal.sendTags(tagsJson);
- threadAndTaskWait();
-
- assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method);
- assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url);
- assertEquals(tagsJson.toString(), emailPut.payload.getJSONObject("tags").toString());
- }
-
- @Test
- public void shouldSetEmailWithAuthHash() throws Exception {
- OneSignalInit();
- String email = "josh@onesignal.com";
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setEmail(email, mockEmailHash);
- threadAndTaskWait();
-
- JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
- assertEquals(email, emailPost.getString("identifier"));
- assertEquals(11, emailPost.getInt("device_type"));
- assertEquals(mockEmailHash, emailPost.getString("email_auth_hash"));
- }
-
- private class TestEmailUpdateHandler implements OneSignal.EmailUpdateHandler {
- boolean emailFiredSuccess = false;
- OneSignal.EmailUpdateError emailFiredFailure = null;
-
- @Override
- public void onSuccess() {
- emailFiredSuccess = true;
- }
-
- @Override
- public void onFailure(OneSignal.EmailUpdateError error) {
- emailFiredFailure = error;
- }
- }
-
- @Test
- public void shouldFireOnSuccessOfEmailUpdate() throws Exception {
- OneSignalInit();
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
- OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
- assertFalse(testEmailUpdateHandler.emailFiredSuccess);
- threadAndTaskWait();
-
- assertTrue(testEmailUpdateHandler.emailFiredSuccess);
- assertNull(testEmailUpdateHandler.emailFiredFailure);
- }
-
- @Test
- public void shouldFireOnSuccessOfEmailEvenWhenNoChanges() throws Exception {
- OneSignalInit();
- String email = "josh@onesignal.com";
- OneSignal.setEmail(email);
- threadAndTaskWait();
-
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
- OneSignal.setEmail(email, testEmailUpdateHandler);
- threadAndTaskWait();
-
- assertTrue(testEmailUpdateHandler.emailFiredSuccess);
- assertNull(testEmailUpdateHandler.emailFiredFailure);
- }
-
- @Test
- public void shouldFireOnFailureOfEmailUpdateOnNetworkFailure() throws Exception {
- OneSignalInit();
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
- OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
- ShadowOneSignalRestClient.failAll = true;
- threadAndTaskWait();
-
- assertFalse(testEmailUpdateHandler.emailFiredSuccess);
- assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType());
- }
-
- @Test
- public void shouldFireOnSuccessOnlyAfterNetworkCallAfterLogout() throws Exception {
- OneSignalInit();
- emailSetThenLogout();
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
- OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
- assertFalse(testEmailUpdateHandler.emailFiredSuccess);
- threadAndTaskWait();
-
- assertTrue(testEmailUpdateHandler.emailFiredSuccess);
- assertNull(testEmailUpdateHandler.emailFiredFailure);
- }
-
- // Should create a new email instead of updating existing player record when no auth hash
- @Test
- public void shouldDoPostOnEmailChange() throws Exception {
- OneSignalInit();
-
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533";
- ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId;
- String newEmail = "different@email.com";
- OneSignal.setEmail(newEmail);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals(newEmail, emailPost.payload.get("identifier"));
-
- ShadowOneSignalRestClient.Request playerPut = ShadowOneSignalRestClient.requests.get(6);
- assertEquals(newMockEmailPlayerId, playerPut.payload.get("parent_player_id"));
- }
-
- // Should update player with new email instead of creating a new one when auth hash is provided
- @Test
- public void shouldUpdateEmailWhenAuthHashIsUsed() throws Exception {
- OneSignalInit();
- String email = "josh@onesignal.com";
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setEmail(email, mockEmailHash);
- threadAndTaskWait();
- OneSignal.setEmail("different@email.com", mockEmailHash);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request pushPut = ShadowOneSignalRestClient.requests.get(4);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, pushPut.method);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", pushPut.url);
- assertEquals("different@email.com", pushPut.payload.get("email"));
-
- ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method);
- assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url);
- assertEquals("different@email.com", emailPut.payload.get("identifier"));
- }
-
- @Test
- public void shouldSendEmailAuthHashWithLogout() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
- OneSignal.setEmail("josh@onesignal.com", mockEmailHash);
- threadAndTaskWait();
-
- OneSignal.logoutEmail();
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", emailPut.url);
- assertEquals(mockEmailHash, emailPut.payload.get("email_auth_hash"));
- }
-
- private void emailSetThenLogout() throws Exception {
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- OneSignal.logoutEmail();
- threadAndTaskWait();
- }
-
- @Test
- public void shouldLogoutOfEmail() throws Exception {
- OneSignalInit();
-
- emailSetThenLogout();
-
- ShadowOneSignalRestClient.Request logoutEmailPost = ShadowOneSignalRestClient.requests.get(4);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", logoutEmailPost.url);
- assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", logoutEmailPost.payload.get("parent_player_id"));
- assertEquals("b4f7f966-d8cc-11e4-bed1-df8f05be55ba", logoutEmailPost.payload.get("app_id"));
- }
-
- @Test
- public void logoutEmailShouldNotSendEmailPlayersRequest() throws Exception {
- // 1. Init OneSignal and set email
- OneSignalInit();
-
- emailSetThenLogout();
-
- time.advanceSystemAndElapsedTimeBy(60);
- pauseActivity(blankActivityController);
- assertAndRunSyncService();
-
- List requests = ShadowOneSignalRestClient.requests;
- assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4);
- assertNotEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", postPush.url);
-
- ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postEmail.url);
- }
-
- @Test
- public void shouldFireOnSuccessOfLogoutEmail() throws Exception {
- OneSignalInit();
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
-
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
- OneSignal.logoutEmail(testEmailUpdateHandler);
- threadAndTaskWait();
-
- assertTrue(testEmailUpdateHandler.emailFiredSuccess);
- assertNull(testEmailUpdateHandler.emailFiredFailure);
- }
-
- @Test
- public void shouldFireOnFailureOfLogoutEmailOnNetworkFailure() throws Exception {
- OneSignalInit();
- TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
-
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.failAll = true;
- OneSignal.logoutEmail(testEmailUpdateHandler);
- threadAndTaskWait();
-
- assertFalse(testEmailUpdateHandler.emailFiredSuccess);
- assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType());
- }
-
- @Test
- public void shouldCreateNewEmailAfterLogout() throws Exception {
- OneSignalInit();
-
- emailSetThenLogout();
-
- String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533";
- ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId;
- OneSignal.setEmail("different@email.com");
- threadAndTaskWait();
-
- // Update Push record's email field.
- ShadowOneSignalRestClient.Request putPushEmail = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, putPushEmail.method);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", putPushEmail.url);
- assertEquals("different@email.com", putPushEmail.payload.get("email"));
-
- // Create new Email record
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals("different@email.com", emailPost.payload.get("identifier"));
-
- // Update Push record's parent_player_id
- ShadowOneSignalRestClient.Request playerPut2 = ShadowOneSignalRestClient.requests.get(7);
- assertEquals(newMockEmailPlayerId, playerPut2.payload.get("parent_player_id"));
- }
-
- @Test
- public void shouldSendOnSessionToEmail() throws Exception {
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- restartAppAndElapseTimeToNextSession(time);
- OneSignalInit();
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
- assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_session", emailPost.url);
- }
-
@Test
public void shouldNotSendTagOnRepeats() throws Exception {
OneSignalInit();
@@ -2973,8 +2593,9 @@ public void testOmitDeletesOfNonExistingKeys() throws Exception {
assertFalse(ShadowOneSignalRestClient.lastPost.has("tags"));
}
-
+ // ####### End DeleteTags Tests ######
// ####### GetTags Tests ########
+
@Test
public void testGetTagsWithNoTagsShouldBeNull() throws Exception {
OneSignalInit();
@@ -3087,45 +2708,7 @@ public void getTagsDelayedAfterRegistering() throws Exception {
assertTrue(ShadowOneSignalRestClient.lastUrl.contains(ShadowOneSignalRestClient.pushUserId));
}
- // ####### on_focus Tests ########
-
- @Test
- public void sendsOnFocus() throws Exception {
- time.advanceSystemAndElapsedTimeBy(0);
- OneSignalInit();
- threadAndTaskWait();
-
- time.advanceSystemAndElapsedTimeBy(60);
- pauseActivity(blankActivityController);
- assertAndRunSyncService();
-
- assertOnFocusAtIndex(2, 60);
- assertRestCalls(3);
- }
-
- @Test
- public void sendsOnFocusToEmail() throws Exception {
- time.advanceSystemAndElapsedTimeBy(0);
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- blankActivityController.resume();
- threadAndTaskWait();
- time.advanceSystemAndElapsedTimeBy(60);
- pauseActivity(blankActivityController);
- assertAndRunSyncService();
-
- assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postPush.url);
- assertEquals(60, postPush.payload.getInt("active_time"));
-
- ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5);
- assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_focus", postEmail.url);
- assertEquals(60, postEmail.payload.getInt("active_time"));
- }
+ // ####### End GetTags Tests ########
/**
* Similar workflow to testLocationPermissionPromptWithPrivacyConsent()
@@ -3262,7 +2845,6 @@ public void shouldReturnCorrectConsentRequiredStatusWhenSetBeforeInit() throws E
assertTrue(OneSignal.userProvidedPrivacyConsent());
}
-
// Functions to add observers (like addSubscriptionObserver) should continue
// to work even if privacy consent has not been granted.
@Test
@@ -3326,30 +2908,58 @@ public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateCh
OneSignal.provideUserConsent(true);
threadAndTaskWait();
- OneSignal.setEmail("josh@onesignal.com");
+ String email = "josh@onesignal.com";
+ OneSignal.setEmail(email);
threadAndTaskWait();
// make sure the email subscription observer was fired
+ assertEquals(email, lastEmailSubscriptionStateChanges.getFrom().getEmailAddress());
assertNull(lastEmailSubscriptionStateChanges.getFrom().getEmailUserId());
assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", lastEmailSubscriptionStateChanges.getTo().getEmailUserId());
- assertEquals("josh@onesignal.com", lastEmailSubscriptionStateChanges.getTo().getEmailAddress());
+ assertEquals(email, lastEmailSubscriptionStateChanges.getTo().getEmailAddress());
assertTrue(lastEmailSubscriptionStateChanges.getTo().isSubscribed());
}
- /*
- // Can't get test to work from a app flow due to the main thread being locked one way or another in a robolectric env.
- // Running ActivityLifecycleListener.focusHandlerThread...advanceToNextPostedRunnable waits on the main thread.
- // If it is put in its own thread then synchronized that is run when messages a runnable is added / removed hangs the main thread here too.
@Test
- public void shouldNotDoubleCountFocusTime() throws Exception {
- System.out.println("TEST IS RUNNING ONE THREAD: " + Thread.currentThread());
-
- // Start app normally
+ public void shouldAddSMSSubscriptionObserverIfConsentNotGranted() throws Exception {
+ ShadowOneSignalRestClient.setRemoteParamsRequirePrivacyConsent(true);
OneSignalInit();
threadAndTaskWait();
- // Press home button after 30 sec
- blankActivityController.resume();
+ OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges;
+ OneSignal.addSMSSubscriptionObserver(subscriptionObserver);
+
+ OneSignal.provideUserConsent(true);
+ threadAndTaskWait();
+
+ assertNull(lastSMSSubscriptionStateChanges);
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // make sure the sms subscription observer was fired
+ assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getFrom().getSMSNumber());
+ assertNull(lastSMSSubscriptionStateChanges.getFrom().getSmsUserId());
+ assertFalse(lastSMSSubscriptionStateChanges.getFrom().isSubscribed());
+ assertEquals(ShadowOneSignalRestClient.smsUserId, lastSMSSubscriptionStateChanges.getTo().getSmsUserId());
+ assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getTo().getSMSNumber());
+ assertTrue(lastSMSSubscriptionStateChanges.getTo().isSubscribed());
+ }
+
+ /*
+ // Can't get test to work from a app flow due to the main thread being locked one way or another in a robolectric env.
+ // Running ActivityLifecycleListener.focusHandlerThread...advanceToNextPostedRunnable waits on the main thread.
+ // If it is put in its own thread then synchronized that is run when messages a runnable is added / removed hangs the main thread here too.
+ @Test
+ public void shouldNotDoubleCountFocusTime() throws Exception {
+ System.out.println("TEST IS RUNNING ONE THREAD: " + Thread.currentThread());
+
+ // Start app normally
+ OneSignalInit();
+ threadAndTaskWait();
+
+ // Press home button after 30 sec
+ blankActivityController.resume();
advanceSystemTimeBy(30 * 1_000L);
blankActivityController.pause();
threadAndTaskWait();
@@ -3383,429 +2993,6 @@ public void shouldNotDoubleCountFocusTime() throws Exception {
}
*/
- // ####### Unit Test Location ########
-
- @Test
- @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
- public void shouldUpdateAllLocationFieldsWhenTimeStampChanges() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
- OneSignalInit();
- threadAndTaskWait();
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
- assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
-
- ShadowOneSignalRestClient.lastPost = null;
- ShadowFusedLocationApiWrapper.lat = 30d;
- ShadowFusedLocationApiWrapper.log = 2.0d;
- ShadowFusedLocationApiWrapper.accuracy = 5.0f;
- ShadowFusedLocationApiWrapper.time = 2L;
- restartAppAndElapseTimeToNextSession(time);
- OneSignalInit();
- threadAndTaskWait();
-
- assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
- assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
- assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
- }
-
- @Test
- @Config(shadows = {ShadowOneSignal.class})
- @SuppressWarnings("unchecked") // getDeclaredMethod
- public void testLocationTimeout() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
-
- Class klass = Class.forName("com.onesignal.GMSLocationController");
- Method method = klass.getDeclaredMethod("startFallBackThread");
- method.setAccessible(true);
- method.invoke(null);
- method = klass.getDeclaredMethod("fireFailedComplete");
- method.setAccessible(true);
- method.invoke(null);
- threadAndTaskWait();
-
- assertFalse(ShadowOneSignal.messages.contains("GoogleApiClient timeout"));
- }
-
- @Test
- @Config(shadows = {
- ShadowGoogleApiClientBuilder.class,
- ShadowGoogleApiClientCompatProxy.class,
- ShadowFusedLocationApiWrapper.class },
- sdk = 19)
- public void testLocationSchedule() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_FINE_LOCATION");
- ShadowFusedLocationApiWrapper.lat = 1.0d;
- ShadowFusedLocationApiWrapper.log = 2.0d;
- ShadowFusedLocationApiWrapper.accuracy = 3.0f;
- ShadowFusedLocationApiWrapper.time = 12345L;
-
- // location if we have permission
- OneSignalInit();
- threadAndTaskWait();
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
- assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
-
- // Checking make sure an update is scheduled.
- AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
- Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
- assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
-
- // Setting up a new point and testing it is sent
- Location fakeLocation = new Location("UnitTest");
- fakeLocation.setLatitude(1.1d);
- fakeLocation.setLongitude(2.2d);
- fakeLocation.setAccuracy(3.3f);
- fakeLocation.setTime(12346L);
- ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation);
-
- Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
- assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
-
- assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
- assertEquals("11111111-2222-3333-4444-555555555555", ShadowOneSignalRestClient.lastPost.opt("ad_id"));
-
- // Testing loc_bg
- blankActivityController.pause();
- threadAndTaskWait();
- Robolectric.buildService(FocusDelaySyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
- fakeLocation.setTime(12347L);
- ShadowGMSLocationUpdateListener.provideFakeLocation(fakeLocation);
- Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
- assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
- assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
- assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
- assertEquals("11111111-2222-3333-4444-555555555555", ShadowOneSignalRestClient.lastPost.opt("ad_id"));
- }
-
- @Test
- @Config(shadows = {
- ShadowGoogleApiClientBuilder.class,
- ShadowGoogleApiClientCompatProxy.class,
- ShadowFusedLocationApiWrapper.class },
- sdk = 19)
- public void testLocationFromSyncAlarm() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- ShadowFusedLocationApiWrapper.lat = 1.1d;
- ShadowFusedLocationApiWrapper.log = 2.1d;
- ShadowFusedLocationApiWrapper.accuracy = 3.1f;
- ShadowFusedLocationApiWrapper.time = 12346L;
-
- OneSignalInit();
- threadAndTaskWait();
-
- fastColdRestartApp();
- AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- shadowOf(alarmManager).getScheduledAlarms().clear();
- ShadowOneSignalRestClient.lastPost = null;
-
- ShadowFusedLocationApiWrapper.lat = 1.0;
- ShadowFusedLocationApiWrapper.log = 2.0d;
- ShadowFusedLocationApiWrapper.accuracy = 3.0f;
- ShadowFusedLocationApiWrapper.time = 12345L;
-
- blankActivityController.pause();
- threadAndTaskWait();
- Robolectric.buildService(FocusDelaySyncService.class, new Intent()).startCommand(0, 0);
- threadAndTaskWait();
- Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0);
- threadAndTaskWait();
-
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
- assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
- assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp"));
- assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
-
- // Checking make sure an update is scheduled.
- alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
- Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
- assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
- shadowOf(alarmManager).getScheduledAlarms().clear();
- }
-
- @Test
- @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
- public void shouldSendLocationToEmailRecord() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload;
- assertEquals(11, postEmailPayload.getInt("device_type"));
- assertEquals(1.0, postEmailPayload.getDouble("lat"));
- assertEquals(2.0, postEmailPayload.getDouble("long"));
- assertEquals(3.0, postEmailPayload.getDouble("loc_acc"));
- assertEquals(0.0, postEmailPayload.getDouble("loc_type"));
- }
-
- @Test
- @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
- public void shouldRegisterWhenPromptingAfterInit() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
- ShadowGoogleApiClientCompatProxy.skipOnConnected = true;
-
- // Test promptLocation right after init race condition
- OneSignalInit();
- OneSignal.promptLocation();
-
- ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1);
- assertEquals(REST_METHOD.POST, request.method);
- assertEquals(1, request.payload.get("device_type"));
- assertEquals(ShadowPushRegistratorFCM.regId, request.payload.get("identifier"));
- }
-
- @Test
- @Config(shadows = {ShadowGoogleApiClientBuilder.class, ShadowGoogleApiClientCompatProxy.class, ShadowFusedLocationApiWrapper.class})
- public void shouldCallOnSessionEvenIfSyncJobStarted() throws Exception {
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- OneSignalInit();
- threadAndTaskWait();
-
- restartAppAndElapseTimeToNextSession(time);
- ShadowGoogleApiClientCompatProxy.skipOnConnected = true;
- OneSignalInit();
-
- SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get();
- syncJobService.onStartJob(null);
- TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join();
- OneSignalPackagePrivateHelper.runAllNetworkRunnables();
- ShadowGoogleApiClientBuilder.connectionCallback.onConnected(null);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3);
- assertEquals(REST_METHOD.POST, request.method);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url);
- }
-
- // ####### Unit Test Huawei Location ########
-
- @Test
- @Config(shadows = {ShadowHMSFusedLocationProviderClient.class})
- public void shouldUpdateAllLocationFieldsWhenTimeStampChanges_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
- OneSignalInit();
- threadAndTaskWait();
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
- assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
-
- ShadowOneSignalRestClient.lastPost = null;
- ShadowHMSFusedLocationProviderClient.resetStatics();
- ShadowHMSFusedLocationProviderClient.lat = 30d;
- ShadowHMSFusedLocationProviderClient.log = 2.0d;
- ShadowHMSFusedLocationProviderClient.accuracy = 5.0f;
- ShadowHMSFusedLocationProviderClient.time = 2L;
- restartAppAndElapseTimeToNextSession(time);
- OneSignalInit();
- threadAndTaskWait();
-
- assertEquals(30.0, ShadowOneSignalRestClient.lastPost.getDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.getDouble("long"));
- assertEquals(5.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_acc"));
- assertEquals(0.0, ShadowOneSignalRestClient.lastPost.getDouble("loc_type"));
- }
-
- @Test
- @Config(shadows = {
- ShadowHMSFusedLocationProviderClient.class
- }, sdk = 19)
- public void testLocationSchedule_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_FINE_LOCATION");
- ShadowHMSFusedLocationProviderClient.lat = 1.0d;
- ShadowHMSFusedLocationProviderClient.log = 2.0d;
- ShadowHMSFusedLocationProviderClient.accuracy = 3.0f;
- ShadowHMSFusedLocationProviderClient.time = 12345L;
-
- // location if we have permission
- OneSignalInit();
- threadAndTaskWait();
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
- assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
-
- // Checking make sure an update is scheduled.
- AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
- Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
- assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
-
- // Setting up a new point and testing it is sent
- HWLocation fakeLocation = new HWLocation();
- fakeLocation.setLatitude(1.1d);
- fakeLocation.setLongitude(2.2d);
- fakeLocation.setAccuracy(3.3f);
- fakeLocation.setTime(12346L);
- ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation);
-
- Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
- assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
-
- assertEquals(false, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
- // Currently not getting ad_id for HMS devices
- assertNull(ShadowOneSignalRestClient.lastPost.opt("ad_id"));
-
- // Testing loc_bg
- blankActivityController.pause();
- threadAndTaskWait();
- Robolectric.buildService(FocusDelaySyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
-
- fakeLocation.setTime(12347L);
- ShadowHMSLocationUpdateListener.provideFakeLocation_Huawei(fakeLocation);
- Robolectric.buildService(SyncService.class, intent).startCommand(0, 0);
- threadAndTaskWait();
- assertEquals(1.1d, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.2d, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.3f, ShadowOneSignalRestClient.lastPost.opt("loc_acc"));
- assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
- assertEquals(1, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
- // Currently not getting ad_id for HMS devices
- assertNull(ShadowOneSignalRestClient.lastPost.opt("ad_id"));
- }
-
- @Test
- @Config(shadows = {
- ShadowHMSFusedLocationProviderClient.class,
- ShadowHuaweiTask.class
- }, sdk = 19)
- public void testLocationFromSyncAlarm_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- ShadowHMSFusedLocationProviderClient.lat = 1.1d;
- ShadowHMSFusedLocationProviderClient.log = 2.1d;
- ShadowHMSFusedLocationProviderClient.accuracy = 3.1f;
- ShadowHMSFusedLocationProviderClient.time = 12346L;
-
- OneSignalInit();
- threadAndTaskWait();
-
- fastColdRestartApp();
- AlarmManager alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- shadowOf(alarmManager).getScheduledAlarms().clear();
-
- ShadowOneSignalRestClient.lastPost = null;
- ShadowHMSFusedLocationProviderClient.resetStatics();
- ShadowHMSFusedLocationProviderClient.lat = 1.0;
- ShadowHMSFusedLocationProviderClient.log = 2.0d;
- ShadowHMSFusedLocationProviderClient.accuracy = 3.0f;
- ShadowHMSFusedLocationProviderClient.time = 12345L;
- ShadowHMSFusedLocationProviderClient.shadowTask = true;
- ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation();
-
- Robolectric.buildService(SyncService.class, new Intent()).startCommand(0, 0);
- threadAndTaskWait();
-
- assertEquals(1.0, ShadowOneSignalRestClient.lastPost.optDouble("lat"));
- assertEquals(2.0, ShadowOneSignalRestClient.lastPost.optDouble("long"));
- assertEquals(3.0, ShadowOneSignalRestClient.lastPost.optDouble("loc_acc"));
- assertEquals(0, ShadowOneSignalRestClient.lastPost.optInt("loc_type"));
- assertEquals(12345L, ShadowOneSignalRestClient.lastPost.optInt("loc_time_stamp"));
- assertEquals(true, ShadowOneSignalRestClient.lastPost.opt("loc_bg"));
-
- // Checking make sure an update is scheduled.
- alarmManager = (AlarmManager)ApplicationProvider.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- assertEquals(1, shadowOf(alarmManager).getScheduledAlarms().size());
- Intent intent = shadowOf(shadowOf(alarmManager).getNextScheduledAlarm().operation).getSavedIntent();
- assertEquals(SyncService.class, shadowOf(intent).getIntentClass());
- shadowOf(alarmManager).getScheduledAlarms().clear();
- }
-
- @Test
- @Config(shadows = {ShadowHMSFusedLocationProviderClient.class})
- public void shouldSendLocationToEmailRecord_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- JSONObject postEmailPayload = ShadowOneSignalRestClient.requests.get(2).payload;
- assertEquals(11, postEmailPayload.getInt("device_type"));
- assertEquals(1.0, postEmailPayload.getDouble("lat"));
- assertEquals(2.0, postEmailPayload.getDouble("long"));
- assertEquals(3.0, postEmailPayload.getDouble("loc_acc"));
- assertEquals(0.0, postEmailPayload.getDouble("loc_type"));
- }
-
- @Test
- @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class})
- public void shouldRegisterWhenPromptingAfterInit_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true;
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- // Test promptLocation right after init race condition
- OneSignalInit();
- OneSignal.promptLocation();
-
- ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation());
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(1);
- assertEquals(REST_METHOD.POST, request.method);
- assertEquals(UserState.DEVICE_TYPE_HUAWEI, request.payload.get("device_type"));
- assertEquals(ShadowHmsInstanceId.token, request.payload.get("identifier"));
- }
-
- @Test
- @Config(shadows = {ShadowHMSFusedLocationProviderClient.class, ShadowHuaweiTask.class})
- public void shouldCallOnSessionEvenIfSyncJobStarted_Huawei() throws Exception {
- ShadowOSUtils.supportsHMS(true);
- ShadowHMSFusedLocationProviderClient.shadowTask = true;
- ShadowHuaweiTask.result = ShadowHMSFusedLocationProviderClient.getLocation();
- ShadowApplication.getInstance().grantPermissions("android.permission.ACCESS_COARSE_LOCATION");
-
- OneSignalInit();
- threadAndTaskWait();
-
- restartAppAndElapseTimeToNextSession(time);
- ShadowHMSFusedLocationProviderClient.skipOnGetLocation = true;
- OneSignalInit();
-
- SyncJobService syncJobService = Robolectric.buildService(SyncJobService.class).create().get();
- syncJobService.onStartJob(null);
- TestHelpers.getThreadByName("OS_SYNCSRV_BG_SYNC").join();
- OneSignalPackagePrivateHelper.runAllNetworkRunnables();
- ShadowHuaweiTask.callSuccessListener(ShadowHMSFusedLocationProviderClient.getLocation());
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request request = ShadowOneSignalRestClient.requests.get(3);
- assertEquals(REST_METHOD.POST, request.method);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_session", request.url);
- }
-
// ####### Unit test postNotification #####
private static JSONObject postNotificationSuccess = null, postNotificationFailure = null;
@@ -3846,7 +3033,6 @@ public void onFailure(JSONObject response) {
assertNotNull(postNotificationFailure);
}
-
@Test
@Config(shadows = { ShadowRoboNotificationManager.class, ShadowBadgeCountUpdater.class, ShadowGenerateNotification.class })
public void shouldCancelAndClearNotifications() throws Exception {
@@ -4120,8 +3306,6 @@ public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) {
assertNull(lastSubscriptionStateChanges);
}
- private OSEmailSubscriptionStateChanges lastEmailSubscriptionStateChanges;
-
@Test
public void shouldFireEmailSubscriptionObserverOnSetEmail() throws Exception {
OneSignalInit();
@@ -4141,6 +3325,20 @@ public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateCh
assertTrue(lastEmailSubscriptionStateChanges.getTo().isSubscribed());
}
+ @Test
+ public void shouldFireSMSSubscriptionObserverOnSetSMS() throws Exception {
+ OneSignalInit();
+ OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges;
+ OneSignal.addSMSSubscriptionObserver(subscriptionObserver);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ assertNull(lastSMSSubscriptionStateChanges.getFrom().getSmsUserId());
+ assertEquals(SMS_USER_ID, lastSMSSubscriptionStateChanges.getTo().getSmsUserId());
+ assertEquals(ONESIGNAL_SMS_NUMBER, lastSMSSubscriptionStateChanges.getTo().getSMSNumber());
+ assertTrue(lastSMSSubscriptionStateChanges.getTo().isSubscribed());
+ }
+
@Test
public void shouldFireEmailSubscriptionObserverOnLogoutEmail() throws Exception {
OneSignalInit();
@@ -4192,6 +3390,28 @@ public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateCh
assertNull(lastEmailSubscriptionStateChanges);
}
+ @Test
+ public void shouldNotFireSMSSubscriptionObserverOnAppRestart() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ OSSMSSubscriptionObserver subscriptionObserver = stateChanges -> lastSMSSubscriptionStateChanges = stateChanges;
+ OneSignal.addSMSSubscriptionObserver(subscriptionObserver);
+ threadAndTaskWait();
+ assertNotNull(lastSMSSubscriptionStateChanges);
+
+ restartAppAndElapseTimeToNextSession(time);
+ lastSMSSubscriptionStateChanges = null;
+
+ OneSignalInit();
+ threadAndTaskWait();
+ OneSignal.addSMSSubscriptionObserver(subscriptionObserver);
+ threadAndTaskWait();
+
+ assertNull(lastSMSSubscriptionStateChanges);
+ }
+
@Test
public void shouldGetCorrectCurrentEmailSubscriptionState() throws Exception {
OneSignalInit();
@@ -4211,6 +3431,25 @@ public void shouldGetCorrectCurrentEmailSubscriptionState() throws Exception {
assertTrue(deviceState.isEmailSubscribed());
}
+ @Test
+ public void shouldGetCorrectCurrentSMSSubscriptionState() throws Exception {
+ OneSignalInit();
+ OSDeviceState deviceState = OneSignal.getDeviceState();
+
+ assertNotNull(deviceState);
+ assertNull(deviceState.getSMSUserId());
+ assertNull(deviceState.getSMSNumber());
+ assertFalse(deviceState.isSMSSubscribed());
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+ deviceState = OneSignal.getDeviceState();
+
+ assertEquals(SMS_USER_ID, deviceState.getSMSUserId());
+ assertEquals(ONESIGNAL_SMS_NUMBER, deviceState.getSMSNumber());
+ assertTrue(deviceState.isSMSSubscribed());
+ }
+
@Test
public void shouldGetEmailUserIdAfterAppRestart() throws Exception {
OneSignalInit();
@@ -4225,6 +3464,20 @@ public void shouldGetEmailUserIdAfterAppRestart() throws Exception {
assertNotNull(deviceState.getEmailUserId());
}
+ @Test
+ public void shouldGetSMSUserIdAfterAppRestart() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ restartAppAndElapseTimeToNextSession(time);
+
+ OneSignalInit();
+ OSDeviceState deviceState = OneSignal.getDeviceState();
+ assertEquals(ONESIGNAL_SMS_NUMBER, deviceState.getSMSNumber());
+ assertNotNull(deviceState.getSMSUserId());
+ }
+
@Test
public void shouldReturnCorrectGetPermissionSubscriptionState() throws Exception {
OneSignalInit();
@@ -4235,623 +3488,47 @@ public void shouldReturnCorrectGetPermissionSubscriptionState() throws Exception
}
@Test
- public void shouldSendPurchases() throws Exception {
- OneSignalInit();
- OneSignal.setEmail("josh@onesignal.com");
- threadAndTaskWait();
-
- JSONObject purchase = new JSONObject();
- purchase.put("sku", "com.test.sku");
- JSONArray purchases = new JSONArray();
- purchases.put(purchase);
-
- OneSignalPackagePrivateHelper.OneSignal_sendPurchases(purchases, false, null);
- threadAndTaskWait();
-
- String expectedPayload = "{\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\",\"purchases\":[{\"sku\":\"com.test.sku\"}]}";
- ShadowOneSignalRestClient.Request pushPurchase = ShadowOneSignalRestClient.requests.get(4);
- assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_purchase", pushPurchase.url);
- assertEquals(expectedPayload, pushPurchase.payload.toString());
-
- ShadowOneSignalRestClient.Request emailPurchase = ShadowOneSignalRestClient.requests.get(5);
- assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_purchase", emailPurchase.url);
- assertEquals(expectedPayload, emailPurchase.payload.toString());
- }
-
- @Test
- @Config(shadows = { ShadowFirebaseAnalytics.class })
- public void shouldSendFirebaseAnalyticsNotificationOpen() throws Exception {
- ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true));
- OneSignalInit();
- threadAndTaskWait();
-
- JSONObject openPayload = new JSONObject();
- openPayload.put("title", "Test title");
- openPayload.put("alert", "Test Msg");
- openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }"));
- OneSignal_handleNotificationOpen(blankActivity, new JSONArray().put(openPayload), false, ONESIGNAL_NOTIFICATION_ID);
-
- assertEquals("os_notification_opened", ShadowFirebaseAnalytics.lastEventString);
- Bundle expectedBundle = new Bundle();
- expectedBundle.putString("notification_id", "UUID");
- expectedBundle.putString("medium", "notification");
- expectedBundle.putString("source", "OneSignal");
- expectedBundle.putString("campaign", "Test title");
- assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString());
-
- // Assert that another open isn't trigger later when the unprocessed opens are fired
- ShadowFirebaseAnalytics.lastEventString = null;
- OneSignal.setAppId(ONESIGNAL_APP_ID);
- OneSignal.initWithContext(blankActivity);
- OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
- assertNull(ShadowFirebaseAnalytics.lastEventString);
- }
-
- @Test
- @Config(shadows = { ShadowFirebaseAnalytics.class, ShadowGenerateNotification.class })
- public void shouldSendFirebaseAnalyticsNotificationReceived() throws Exception {
- ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true));
- OneSignalInit();
- threadAndTaskWait();
-
- JSONObject openPayload = new JSONObject();
- openPayload.put("title", "Test title");
- openPayload.put("alert", "Test Msg");
- openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }"));
- NotificationBundleProcessor_Process(blankActivity, false, openPayload);
-
- assertEquals("os_notification_received", ShadowFirebaseAnalytics.lastEventString);
- Bundle expectedBundle = new Bundle();
- expectedBundle.putString("notification_id", "UUID");
- expectedBundle.putString("medium", "notification");
- expectedBundle.putString("source", "OneSignal");
- expectedBundle.putString("campaign", "Test title");
- assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString());
-
- // Assert that another receive isn't trigger later when the unprocessed receives are fired
- OneSignal.setAppId(ONESIGNAL_APP_ID);
- OneSignal.initWithContext(blankActivity);
- OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent -> {
-
- });
- OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
- threadAndTaskWait();
-
- ShadowFirebaseAnalytics.lastEventString = null;
- OneSignal.setAppId(ONESIGNAL_APP_ID);
- OneSignal.initWithContext(blankActivity);
- OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
- assertNull(ShadowFirebaseAnalytics.lastEventString);
- }
-
- @Test
- public void shouldSendExternalUserIdAfterRegistration() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
-
- String testExternalId = "test_ext_id";
-
- OneSignal.setExternalUserId(testExternalId);
-
- threadAndTaskWait();
-
- assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method);
- assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id"));
- }
-
- @Test
- public void shouldSendExternalUserIdBeforeRegistration() throws Exception {
- String testExternalId = "test_ext_id";
-
- OneSignal.setExternalUserId(testExternalId);
-
- OneSignalInit();
- threadAndTaskWait();
-
- assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method);
- assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
- }
-
- @Test
- public void shouldSetExternalIdWithAuthHash() throws Exception {
- ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("require_user_id_auth", true));
-
- OneSignalInit();
- threadAndTaskWait();
-
- String testExternalId = "test_ext_id";
-
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- assertNotNull(lastExternalUserIdError);
- assertEquals(REQUIRES_EXTERNAL_ID_AUTH, lastExternalUserIdError.getType());
- }
-
- @Test
- public void shouldSetExternalIdWithAuthHashAfterRegistration() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
-
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
- threadAndTaskWait();
-
- assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method);
- assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id"));
- assertEquals(mockExternalIdHash, externalIdRequest.payload.getString("external_user_id_auth_hash"));
- }
-
- @Test
- public void shouldSetExternalIdWithAuthHashBeforeRegistration() throws Exception {
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
-
- OneSignalInit();
- threadAndTaskWait();
-
- assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method);
- assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
- assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
- }
-
- @Test
- public void shouldAlwaysSetExternalIdWithAuthHashAAfterRegistration() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
-
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method);
- assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
- assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
-
- fastColdRestartApp();
-
- time.advanceSystemTimeBy(60);
- OneSignalInit();
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(4);
- assertEquals(REST_METHOD.POST, registrationRequestAfterColdStart.method);
- assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash"));
- }
-
- @Test
- public void shouldAlwaysSetExternalIdAndEmailWithAuthHashAfterRegistration() throws Exception {
- OneSignalInit();
- threadAndTaskWait();
-
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
-
- String email = "josh@onesignal.com";
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
- OneSignal.setEmail(email, mockEmailHash);
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method);
- assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
- assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
-
- ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(3);
- assertEquals(REST_METHOD.POST, emailPost.method);
- assertEquals(email, emailPost.payload.getString("identifier"));
- assertEquals(11, emailPost.payload.getInt("device_type"));
- assertEquals(mockEmailHash, emailPost.payload.getString("email_auth_hash"));
-
- fastColdRestartApp();
-
- time.advanceSystemTimeBy(60);
- OneSignalInit();
- threadAndTaskWait();
-
- ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(6);
- assertEquals(REST_METHOD.POST, registrationRequestAfterColdStart.method);
- assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash"));
-
- ShadowOneSignalRestClient.Request emailPostAfterColdStart = ShadowOneSignalRestClient.requests.get(7);
- assertEquals(REST_METHOD.POST, emailPostAfterColdStart.method);
- assertEquals(11, emailPostAfterColdStart.payload.getInt("device_type"));
- assertEquals(mockEmailHash, emailPostAfterColdStart.payload.getString("email_auth_hash"));
- }
-
- @Test
- public void shouldRemoveExternalUserId() throws Exception {
- OneSignal.setExternalUserId("test_ext_id");
-
- OneSignalInit();
- threadAndTaskWait();
-
- OneSignal.removeExternalUserId();
- threadAndTaskWait();
-
- assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
- assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
- }
-
- @Test
- public void shouldRemoveExternalUserIdFromPushWithAuthHash() throws Exception {
- ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("require_user_id_auth", true));
-
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
- OneSignalInit();
- threadAndTaskWait();
-
- OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
-
- assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
- assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
- assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
- }
-
- @Test
- public void shouldRemoveExternalUserIdFromEmailWithAuthHash() throws Exception {
- String testEmail = "test@test.com";
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setEmail(testEmail, mockEmailHash, getEmailUpdateHandler());
- OneSignalInit();
- threadAndTaskWait();
-
- OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" + ", " +
- " \"email\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
- assertTrue(didEmailUpdateSucceed);
- assertNull(lastEmailUpdateFailure);
-
- assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
- assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
- assertFalse(removeIdRequest.payload.has("external_user_id_auth_hash"));
-
- ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method);
- assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), "");
- assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash"));
- }
-
- @Test
- public void shouldRemoveExternalUserIdFromPushAndEmailWithAuthHash() throws Exception {
- String testExternalId = "test_ext_id";
- String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
- String testEmail = "test@test.com";
- String mockEmailHash = new String(new char[64]).replace('\0', '0');
-
- OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
- OneSignal.setEmail(testEmail, mockEmailHash, null);
- OneSignalInit();
- threadAndTaskWait();
-
- OneSignal.removeExternalUserId();
- threadAndTaskWait();
-
- assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
-
- ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
- assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
- assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
-
- ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5);
- assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method);
- assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), "");
- assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash"));
- }
-
- @Test
- public void doesNotSendSameExternalId() throws Exception {
- String testExternalId = "test_ext_id";
- OneSignal.setExternalUserId(testExternalId);
-
- OneSignalInit();
- threadAndTaskWait();
-
- assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
-
- OneSignal.setExternalUserId(testExternalId);
- threadAndTaskWait();
-
- // Setting the same ID again should not generate a duplicate API request
- // The SDK should detect it is the same and not generate a request
- assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
- }
-
- @Test
- public void sendsExternalIdOnEmailPlayers() throws Exception {
- String testExternalId = "test_ext_id";
-
- OneSignalInit();
- threadAndTaskWait();
-
- OneSignal.setEmail("brad@onesignal.com");
- threadAndTaskWait();
-
- int currentRequestCount = ShadowOneSignalRestClient.networkCallCount;
-
- OneSignal.setExternalUserId(testExternalId);
- threadAndTaskWait();
-
- // the SDK should have made two additional API calls
- // One to set extID on the push player record,
- // and another for the email player record
- assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 2);
-
- int externalIdRequests = 0;
-
- for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) {
- if (request.payload != null && request.payload.has("external_user_id")) {
- externalIdRequests += 1;
- assertEquals(request.payload.getString("external_user_id"), testExternalId);
- }
- }
-
- assertEquals(externalIdRequests, 2);
- }
-
- @Test
- public void sendExternalUserId_withCompletionHandler() throws Exception {
- String testExternalId = "test_ext_id";
-
- // 1. Init OneSignal
- OneSignalInit();
- threadAndTaskWait();
-
- // 2. Attempt to set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 3. Make sure lastExternalUserIdResponse is equal to the expected response
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
- }
-
- @Test
- public void sendDifferentExternalUserId_withCompletionHandler() throws Exception {
- String testExternalId = "test_ext_id_1";
-
- // 1. Init OneSignal
- OneSignalInit();
- threadAndTaskWait();
-
- // 2. Attempt to set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 3. Make sure lastExternalUserIdResponse is equal to the expected response
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
-
- // 4. Change test external user id to send
- testExternalId = "test_ext_id_2";
-
- // 5. Attempt to set same exact external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 6. Make sure lastExternalUserIdResponse is equal to the expected response
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
- }
-
- @Test
- public void sendSameExternalUserId_withCompletionHandler() throws Exception {
- String testExternalId = "test_ext_id";
-
- // 1. Init OneSignal
- OneSignalInit();
- threadAndTaskWait();
-
- // 2. Attempt to set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 3. Make sure lastExternalUserIdResponse is equal to the expected response
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
-
- // 4. Attempt to set same exact external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 5. Make sure lastExternalUserIdResponse is equal to the expected response
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
- }
+ public void testDeviceStateHasEmailAddress() throws Exception {
+ String testEmail = "test@onesignal.com";
- @Test
- public void sendExternalUserId_withFailure_withCompletionHandler() throws Exception {
- String testExternalId = "test_ext_id";
+ assertNull(OneSignal.getDeviceState());
- // 1. Init OneSignal
OneSignalInit();
threadAndTaskWait();
- // 2. Attempt to set external user id with callback and force failure on the network requests
- ShadowOneSignalRestClient.failAll = true;
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 3. Make sure lastExternalUserIdResponse is equal to the expected response
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : false" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
-
- // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
- ShadowOneSignalRestClient.failAll = false;
-
- // 5. Attempt a second set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 6. Make sure lastExternalUserIdResponse is equal to the expected response
- expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
- }
-
- @Test
- public void sendExternalUserId_forPushAndEmail_withFailure_withCompletionHandler() throws Exception {
- String testEmail = "test@onesignal.com";
- String testExternalId = "test_ext_id";
+ OSDeviceState device = OneSignal.getDeviceState();
+ assertNull(device.getEmailAddress());
- // 1. Init OneSignal
- OneSignalInit();
OneSignal.setEmail(testEmail);
threadAndTaskWait();
- // 2. Attempt to set external user id with callback and force failure on the network requests
- ShadowOneSignalRestClient.failAll = true;
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 3. Make sure lastExternalUserIdResponse has push and email with success : false
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : false" +
- " }," +
- " \"email\" : {" +
- " \"success\" : false" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
-
- // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
- ShadowOneSignalRestClient.failAll = false;
-
- // 5. Attempt a second set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
- threadAndTaskWait();
-
- // 6. Make sure lastExternalUserIdResponse has push and email with success : true
- expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }," +
- " \"email\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ // Device is a snapshot, last value should not change
+ assertNull(device.getEmailAddress());
+ // Retrieve new user device
+ assertEquals(testEmail, OneSignal.getDeviceState().getEmailAddress());
}
@Test
- public void sendExternalUserId_forPush_afterLoggingOutEmail_withCompletion() throws Exception {
- String testEmail = "test@onesignal.com";
- String testExternalId = "test_ext_id";
+ public void testDeviceStateHasSMSAddress() throws Exception {
+ assertNull(OneSignal.getDeviceState());
- // 1. Init OneSignal and set email
OneSignalInit();
- OneSignal.setEmail(testEmail);
threadAndTaskWait();
- // 2. Logout Email
- OneSignal.logoutEmail();
- threadAndTaskWait();
+ OSDeviceState device = OneSignal.getDeviceState();
+ assertNull(device.getSMSNumber());
- // 4. Attempt a set external user id with callback
- OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
threadAndTaskWait();
- // 5. Make sure lastExternalUserIdResponse has push with success : true
- JSONObject expectedExternalUserIdResponse = new JSONObject(
- "{" +
- " \"push\" : {" +
- " \"success\" : true" +
- " }" +
- "}"
- );
- assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ // Device is a snapshot, last value should not change
+ assertNull(device.getSMSNumber());
+ // Retrieve new user device
+ assertEquals(ONESIGNAL_SMS_NUMBER, OneSignal.getDeviceState().getSMSNumber());
}
@Test
- public void testDeviceStateHasEmailAddress() throws Exception {
+ public void testDeviceStateHasEmailId() throws Exception {
String testEmail = "test@onesignal.com";
assertNull(OneSignal.getDeviceState());
@@ -4860,36 +3537,34 @@ public void testDeviceStateHasEmailAddress() throws Exception {
threadAndTaskWait();
OSDeviceState device = OneSignal.getDeviceState();
- assertNull(device.getEmailAddress());
+ assertNull(device.getEmailUserId());
OneSignal.setEmail(testEmail);
threadAndTaskWait();
// Device is a snapshot, last value should not change
- assertNull(device.getEmailAddress());
+ assertNull(device.getEmailUserId());
// Retrieve new user device
- assertEquals(testEmail, OneSignal.getDeviceState().getEmailAddress());
+ assertNotNull(OneSignal.getDeviceState().getEmailUserId());
}
@Test
- public void testDeviceStateHasEmailId() throws Exception {
- String testEmail = "test@onesignal.com";
-
+ public void testDeviceStateHasSMSId() throws Exception {
assertNull(OneSignal.getDeviceState());
OneSignalInit();
threadAndTaskWait();
OSDeviceState device = OneSignal.getDeviceState();
- assertNull(device.getEmailUserId());
+ assertNull(device.getSMSUserId());
- OneSignal.setEmail(testEmail);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
threadAndTaskWait();
// Device is a snapshot, last value should not change
- assertNull(device.getEmailUserId());
+ assertNull(device.getSMSUserId());
// Retrieve new user device
- assertNotNull(OneSignal.getDeviceState().getEmailUserId());
+ assertEquals(SMS_USER_ID, OneSignal.getDeviceState().getSMSUserId());
}
@Test
@@ -4968,6 +3643,101 @@ public void testDeviceStateIsSubscribed() throws Exception {
assertFalse(OneSignal.getDeviceState().isSubscribed());
}
+ @Test
+ public void shouldSendPurchases() throws Exception {
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ JSONObject purchase = new JSONObject();
+ purchase.put("sku", "com.test.sku");
+ JSONArray purchases = new JSONArray();
+ purchases.put(purchase);
+
+ OneSignalPackagePrivateHelper.OneSignal_sendPurchases(purchases, false, null);
+ threadAndTaskWait();
+
+ String expectedPayload = "{\"app_id\":\"b4f7f966-d8cc-11e4-bed1-df8f05be55ba\",\"purchases\":[{\"sku\":\"com.test.sku\"}]}";
+ ShadowOneSignalRestClient.Request pushPurchase = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals("players/" + PUSH_USER_ID + "/on_purchase", pushPurchase.url);
+ assertEquals(expectedPayload, pushPurchase.payload.toString());
+
+ ShadowOneSignalRestClient.Request emailPurchase = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals("players/" + EMAIL_USER_ID + "/on_purchase", emailPurchase.url);
+ assertEquals(expectedPayload, emailPurchase.payload.toString());
+
+ ShadowOneSignalRestClient.Request smsPurchase = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals("players/" + SMS_USER_ID + "/on_purchase", smsPurchase.url);
+ assertEquals(expectedPayload, smsPurchase.payload.toString());
+ }
+
+ @Test
+ @Config(shadows = { ShadowFirebaseAnalytics.class })
+ public void shouldSendFirebaseAnalyticsNotificationOpen() throws Exception {
+ ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true));
+ OneSignalInit();
+ threadAndTaskWait();
+
+ JSONObject openPayload = new JSONObject();
+ openPayload.put("title", "Test title");
+ openPayload.put("alert", "Test Msg");
+ openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }"));
+ OneSignal_handleNotificationOpen(blankActivity, new JSONArray().put(openPayload), false, ONESIGNAL_NOTIFICATION_ID);
+
+ assertEquals("os_notification_opened", ShadowFirebaseAnalytics.lastEventString);
+ Bundle expectedBundle = new Bundle();
+ expectedBundle.putString("notification_id", "UUID");
+ expectedBundle.putString("medium", "notification");
+ expectedBundle.putString("source", "OneSignal");
+ expectedBundle.putString("campaign", "Test title");
+ assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString());
+
+ // Assert that another open isn't trigger later when the unprocessed opens are fired
+ ShadowFirebaseAnalytics.lastEventString = null;
+ OneSignal.setAppId(ONESIGNAL_APP_ID);
+ OneSignal.initWithContext(blankActivity);
+ OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
+ assertNull(ShadowFirebaseAnalytics.lastEventString);
+ }
+
+ @Test
+ @Config(shadows = { ShadowFirebaseAnalytics.class, ShadowGenerateNotification.class })
+ public void shouldSendFirebaseAnalyticsNotificationReceived() throws Exception {
+ ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("fba", true));
+ OneSignalInit();
+ threadAndTaskWait();
+
+ JSONObject openPayload = new JSONObject();
+ openPayload.put("title", "Test title");
+ openPayload.put("alert", "Test Msg");
+ openPayload.put("custom", new JSONObject("{ \"i\": \"UUID\" }"));
+ NotificationBundleProcessor_Process(blankActivity, false, openPayload);
+
+ assertEquals("os_notification_received", ShadowFirebaseAnalytics.lastEventString);
+ Bundle expectedBundle = new Bundle();
+ expectedBundle.putString("notification_id", "UUID");
+ expectedBundle.putString("medium", "notification");
+ expectedBundle.putString("source", "OneSignal");
+ expectedBundle.putString("campaign", "Test title");
+ assertEquals(expectedBundle.toString(), ShadowFirebaseAnalytics.lastEventBundle.toString());
+
+ // Assert that another receive isn't trigger later when the unprocessed receives are fired
+ OneSignal.setAppId(ONESIGNAL_APP_ID);
+ OneSignal.initWithContext(blankActivity);
+ OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent -> {
+
+ });
+ OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
+ threadAndTaskWait();
+
+ ShadowFirebaseAnalytics.lastEventString = null;
+ OneSignal.setAppId(ONESIGNAL_APP_ID);
+ OneSignal.initWithContext(blankActivity);
+ OneSignal.setNotificationOpenedHandler(getNotificationOpenedHandler());
+ assertNull(ShadowFirebaseAnalytics.lastEventString);
+ }
+
@Test
public void testGetTagsQueuesCallbacks() throws Exception {
final BlockingQueue queue = new ArrayBlockingQueue<>(2);
diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java
index 01824ae8a8..9df09ddd25 100644
--- a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java
+++ b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/RestClientAsserts.java
@@ -33,7 +33,8 @@ class RestClientAsserts {
is(UserState.DEVICE_TYPE_ANDROID),
is(UserState.DEVICE_TYPE_FIREOS),
is(UserState.DEVICE_TYPE_EMAIL),
- is(UserState.DEVICE_TYPE_HUAWEI)
+ is(UserState.DEVICE_TYPE_HUAWEI),
+ is(UserState.DEVICE_TYPE_SMS)
);
private static final AnyOf ANY_OF_PUSH_DEVICE_TYPES = anyOf(
diff --git a/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java
new file mode 100644
index 0000000000..d610c9fc16
--- /dev/null
+++ b/OneSignalSDK/unittest/src/test/java/com/test/onesignal/SynchronizerIntegrationTests.java
@@ -0,0 +1,2095 @@
+package com.test.onesignal;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.onesignal.MockOSLog;
+import com.onesignal.MockOSSharedPreferences;
+import com.onesignal.MockOSTimeImpl;
+import com.onesignal.MockOneSignalDBHelper;
+import com.onesignal.MockSessionManager;
+import com.onesignal.OSDeviceState;
+import com.onesignal.OneSignal;
+import com.onesignal.OneSignalPackagePrivateHelper;
+import com.onesignal.ShadowCustomTabsClient;
+import com.onesignal.ShadowCustomTabsSession;
+import com.onesignal.ShadowGMSLocationController;
+import com.onesignal.ShadowOSUtils;
+import com.onesignal.ShadowOneSignalRestClient;
+import com.onesignal.StaticResetHelper;
+import com.onesignal.example.BlankActivity;
+import com.onesignal.influence.data.OSTrackerFactory;
+
+import org.json.JSONObject;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLog;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import static com.onesignal.OneSignal.ExternalIdErrorType.REQUIRES_EXTERNAL_ID_AUTH;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_getSessionListener;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setSessionManager;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTime;
+import static com.onesignal.OneSignalPackagePrivateHelper.OneSignal_setTrackerFactory;
+import static com.onesignal.ShadowOneSignalRestClient.EMAIL_USER_ID;
+import static com.onesignal.ShadowOneSignalRestClient.PUSH_USER_ID;
+import static com.onesignal.ShadowOneSignalRestClient.SMS_USER_ID;
+import static com.onesignal.ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse;
+import static com.test.onesignal.RestClientAsserts.assertOnFocusAtIndex;
+import static com.test.onesignal.RestClientAsserts.assertRestCalls;
+import static com.test.onesignal.TestHelpers.afterTestCleanup;
+import static com.test.onesignal.TestHelpers.assertAndRunSyncService;
+import static com.test.onesignal.TestHelpers.fastColdRestartApp;
+import static com.test.onesignal.TestHelpers.pauseActivity;
+import static com.test.onesignal.TestHelpers.restartAppAndElapseTimeToNextSession;
+import static com.test.onesignal.TestHelpers.threadAndTaskWait;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertNotEquals;
+
+@Config(packageName = "com.onesignal.example",
+ shadows = {
+ ShadowOneSignalRestClient.class,
+ ShadowOSUtils.class,
+ ShadowCustomTabsClient.class,
+ ShadowCustomTabsSession.class
+ },
+ sdk = 21
+)
+@RunWith(RobolectricTestRunner.class)
+public class SynchronizerIntegrationTests {
+ private static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba";
+ private static final String ONESIGNAL_EMAIL_ADDRESS = "test@onesignal.com";
+ private static final String ONESIGNAL_SMS_NUMBER = "123456789";
+
+ @SuppressLint("StaticFieldLeak")
+ private static Activity blankActivity;
+ private static ActivityController blankActivityController;
+
+ private MockOSTimeImpl time;
+ private OSTrackerFactory trackerFactory;
+ private MockSessionManager sessionManager;
+ private MockOneSignalDBHelper dbHelper;
+
+ private static JSONObject lastExternalUserIdResponse;
+ private static OneSignal.ExternalIdError lastExternalUserIdError;
+
+ private static OneSignal.OSExternalUserIdUpdateCompletionHandler getExternalUserIdUpdateCompletionHandler() {
+ return new OneSignal.OSExternalUserIdUpdateCompletionHandler() {
+ @Override
+ public void onSuccess(JSONObject results) {
+ lastExternalUserIdResponse = results;
+ }
+
+ @Override
+ public void onFailure(OneSignal.ExternalIdError error) {
+ lastExternalUserIdError = error;
+ }
+ };
+ }
+
+ private static boolean didEmailUpdateSucceed;
+ private static OneSignal.EmailUpdateError lastEmailUpdateFailure;
+
+ private static OneSignal.EmailUpdateHandler getEmailUpdateHandler() {
+ return new OneSignal.EmailUpdateHandler() {
+ @Override
+ public void onSuccess() {
+ didEmailUpdateSucceed = true;
+ }
+
+ @Override
+ public void onFailure(OneSignal.EmailUpdateError error) {
+ lastEmailUpdateFailure = error;
+ }
+ };
+ }
+
+ private static JSONObject didSMSlUpdateSucceed;
+ private static OneSignal.OSSMSUpdateError lastSMSUpdateFailure;
+
+ private static OneSignal.OSSMSUpdateHandler getSMSUpdateHandler() {
+ return new OneSignal.OSSMSUpdateHandler() {
+ @Override
+ public void onSuccess(JSONObject result) {
+ didSMSlUpdateSucceed = result;
+ }
+
+ @Override
+ public void onFailure(OneSignal.OSSMSUpdateError error) {
+ lastSMSUpdateFailure = error;
+ }
+ };
+ }
+
+ private static void cleanUp() throws Exception {
+ lastExternalUserIdResponse = null;
+ lastExternalUserIdError = null;
+ lastEmailUpdateFailure = null;
+ didEmailUpdateSucceed = false;
+
+ ShadowGMSLocationController.reset();
+
+ TestHelpers.beforeTestInitAndCleanup();
+
+ // Set remote_params GET response
+ setRemoteParamsGetHtmlResponse();
+ }
+
+ @BeforeClass // Runs only once, before any tests
+ public static void setUpClass() throws Exception {
+ ShadowLog.stream = System.out;
+
+ TestHelpers.beforeTestSuite();
+
+ Field OneSignal_CurrentSubscription = OneSignal.class.getDeclaredField("subscribableStatus");
+ OneSignal_CurrentSubscription.setAccessible(true);
+
+ OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
+ StaticResetHelper.saveStaticValues();
+ }
+
+ @Before
+ public void beforeEachTest() throws Exception {
+ blankActivityController = Robolectric.buildActivity(BlankActivity.class).create();
+ blankActivity = blankActivityController.get();
+ time = new MockOSTimeImpl();
+ trackerFactory = new OSTrackerFactory(new MockOSSharedPreferences(), new MockOSLog(), time);
+ sessionManager = new MockSessionManager(OneSignal_getSessionListener(), trackerFactory, new MockOSLog());
+ dbHelper = new MockOneSignalDBHelper(ApplicationProvider.getApplicationContext());
+
+ TestHelpers.setupTestWorkManager(blankActivity);
+
+ cleanUp();
+
+ OneSignal_setTime(time);
+ }
+
+ @After
+ public void afterEachTest() throws Exception {
+ afterTestCleanup();
+ }
+
+ @AfterClass
+ public static void afterEverything() throws Exception {
+ cleanUp();
+ }
+
+ @Test
+ public void shouldSetEmail() throws Exception {
+ OneSignalInit();
+ String email = "josh@onesignal.com";
+
+ OneSignal.setEmail(email);
+ threadAndTaskWait();
+
+ assertEquals(4, ShadowOneSignalRestClient.networkCallCount);
+
+ JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload;
+ assertEquals(email, pushPost.getString("email"));
+ assertEquals(1, pushPost.getInt("device_type"));
+
+ JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(email, emailPost.getString("identifier"));
+ assertEquals(11, emailPost.getInt("device_type"));
+ assertEquals(ShadowOneSignalRestClient.pushUserId, emailPost.getString("device_player_id"));
+
+ JSONObject pushPut = ShadowOneSignalRestClient.requests.get(3).payload;
+ assertEquals(ShadowOneSignalRestClient.emailUserId, pushPut.getString("parent_player_id"));
+ assertFalse(pushPut.has("identifier"));
+ }
+
+ @Test
+ public void shouldSetSMS() throws Exception {
+ OneSignalInit();
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // NO parent player id call
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload;
+ assertEquals(ONESIGNAL_SMS_NUMBER, pushPost.getString("sms_number"));
+ assertEquals(1, pushPost.getInt("device_type"));
+
+ JSONObject smsPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type"));
+ assertEquals(ShadowOneSignalRestClient.pushUserId, smsPost.getString("device_player_id"));
+ }
+
+ @Test
+ public void shouldSetSMSAndEmail() throws Exception {
+ OneSignalInit();
+
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ JSONObject pushPost = ShadowOneSignalRestClient.requests.get(1).payload;
+ assertEquals(ONESIGNAL_EMAIL_ADDRESS, pushPost.getString("email"));
+ assertEquals(ONESIGNAL_SMS_NUMBER, pushPost.getString("sms_number"));
+ assertEquals(1, pushPost.getInt("device_type"));
+
+ JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.getString("identifier"));
+ assertEquals(11, emailPost.getInt("device_type"));
+ assertEquals(ShadowOneSignalRestClient.pushUserId, emailPost.getString("device_player_id"));
+
+ JSONObject smsPost = ShadowOneSignalRestClient.requests.get(3).payload;
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type"));
+ assertEquals(ShadowOneSignalRestClient.pushUserId, smsPost.getString("device_player_id"));
+
+ JSONObject pushPut = ShadowOneSignalRestClient.requests.get(4).payload;
+ assertEquals(ShadowOneSignalRestClient.emailUserId, pushPut.getString("parent_player_id"));
+ // add email parent id call
+ // TODO: check if this behaviour is not dropped
+ assertFalse(pushPut.has("identifier"));
+ }
+
+ @Test
+ public void shouldSendTagsToEmailBeforeCreate() throws Exception {
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(4, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals("josh@onesignal.com", emailPost.payload.get("identifier"));
+ assertEquals(tagsJson.toString(), emailPost.payload.getJSONObject("tags").toString());
+ }
+
+ @Test
+ public void shouldSendTagsToSMSBeforeCreate() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier"));
+ assertEquals(tagsJson.toString(), smsPost.payload.getJSONObject("tags").toString());
+ }
+
+ @Test
+ public void shouldWaitBeforeCreateEmailIfPushCreateFails() throws Exception {
+ ShadowOneSignalRestClient.failPosts = true;
+
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ // Assert we are sending / retry for the push player first.
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+ for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) {
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(i);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals(1, emailPost.payload.getInt("device_type"));
+ }
+
+ // Turn off fail mocking, call sendTags to trigger another retry
+ ShadowOneSignalRestClient.failPosts = false;
+ OneSignal.sendTag("test", "test");
+ threadAndTaskWait();
+
+ // Should now POST to create device_type 11 (email)
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals("josh@onesignal.com", emailPost.payload.get("identifier"));
+ }
+
+ @Test
+ public void shouldWaitBeforeCreateSMSIfPushCreateFails() throws Exception {
+ ShadowOneSignalRestClient.failPosts = true;
+
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // Assert we are sending / retry for the push player first.
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+ for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) {
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(i);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("sms_number"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_ANDROID, smsPost.payload.getInt("device_type"));
+ }
+
+ // Turn off fail mocking, call sendTags to trigger another retry
+ ShadowOneSignalRestClient.failPosts = false;
+ OneSignal.sendTag("test", "test");
+ threadAndTaskWait();
+
+ // Should now POST to create device_type 14 (sms)
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type"));
+ }
+
+ @Test
+ public void shouldWaitBeforeCreateEmailAndSMSIfPushCreateFails() throws Exception {
+ ShadowOneSignalRestClient.failPosts = true;
+
+ OneSignalInit();
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // Assert we are sending / retry for the push player first.
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+ for (int i = 1; i < ShadowOneSignalRestClient.networkCallCount; i++) {
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(i);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_EMAIL_ADDRESS, smsPost.payload.getString("email"));
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("sms_number"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_ANDROID, smsPost.payload.getInt("device_type"));
+ }
+
+ // Turn off fail mocking, call sendTags to trigger another retry
+ ShadowOneSignalRestClient.failPosts = false;
+ OneSignal.sendTag("test", "test");
+ threadAndTaskWait();
+
+ // Should now POST to create device_type 11 (email)
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.payload.get("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_EMAIL, emailPost.payload.get("device_type"));
+
+ // Should now POST to create device_type 14 (email)
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.get("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type"));
+ }
+
+ @Test
+ public void shouldSendTagsToEmailAfterCreate() throws Exception {
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method);
+ assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url);
+ assertEquals(tagsJson.toString(), emailPut.payload.getJSONObject("tags").toString());
+ }
+
+ @Test
+ public void shouldSendTagsToSMSAfterCreate() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url);
+ assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString());
+ }
+
+ @Test
+ public void shouldSendTagsToSMSWithHashToken() throws Exception {
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash);
+ threadAndTaskWait();
+
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url);
+ assertEquals(3, smsPut.payload.length());
+ assertTrue(smsPut.payload.has("app_id"));
+ assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString());
+ assertEquals(mockSMSHash, smsPut.payload.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldSendTagsToEmailAndSMSAfterCreate() throws Exception {
+ OneSignalInit();
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(8, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.emailUserId, emailPut.url);
+ assertEquals(tagsJson.toString(), emailPut.payload.getJSONObject("tags").toString());
+
+ ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url);
+ assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString());
+ }
+
+ @Test
+ public void shouldSetEmailWithAuthHash() throws Exception {
+ OneSignalInit();
+ String email = "josh@onesignal.com";
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setEmail(email, mockEmailHash);
+ threadAndTaskWait();
+
+ JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(email, emailPost.getString("identifier"));
+ assertEquals(11, emailPost.getInt("device_type"));
+ assertEquals(mockEmailHash, emailPost.getString("email_auth_hash"));
+ }
+
+ @Test
+ public void shouldSetSMSWithAuthHash() throws Exception {
+ OneSignalInit();
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash);
+ threadAndTaskWait();
+
+ JSONObject smsPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type"));
+ assertEquals(mockSMSHash, smsPost.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldSetEmailAndSMSWithAuthHash() throws Exception {
+ OneSignalInit();
+ String mockEmailHash = new String(new char[64]).replace('\0', '1');
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, mockEmailHash);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash);
+ threadAndTaskWait();
+
+ JSONObject emailPost = ShadowOneSignalRestClient.requests.get(2).payload;
+ assertEquals(ONESIGNAL_EMAIL_ADDRESS, emailPost.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_EMAIL, emailPost.getInt("device_type"));
+ assertEquals(mockEmailHash, emailPost.getString("email_auth_hash"));
+
+ JSONObject smsPost = ShadowOneSignalRestClient.requests.get(3).payload;
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.getInt("device_type"));
+ assertEquals(mockSMSHash, smsPost.getString("sms_auth_hash"));
+ }
+
+ private class TestEmailUpdateHandler implements OneSignal.EmailUpdateHandler {
+ boolean emailFiredSuccess = false;
+ OneSignal.EmailUpdateError emailFiredFailure = null;
+
+ @Override
+ public void onSuccess() {
+ emailFiredSuccess = true;
+ }
+
+ @Override
+ public void onFailure(OneSignal.EmailUpdateError error) {
+ emailFiredFailure = error;
+ }
+ }
+
+ private class TestSMSUpdateHandler implements OneSignal.OSSMSUpdateHandler {
+ JSONObject smsResult = null;
+ OneSignal.OSSMSUpdateError smsFiredFailure = null;
+
+ @Override
+ public void onSuccess(JSONObject result) {
+ smsResult = result;
+ }
+
+ @Override
+ public void onFailure(OneSignal.OSSMSUpdateError error) {
+ smsFiredFailure = error;
+ }
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfEmailUpdate() throws Exception {
+ OneSignalInit();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+ OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
+ assertFalse(testEmailUpdateHandler.emailFiredSuccess);
+ threadAndTaskWait();
+
+ assertTrue(testEmailUpdateHandler.emailFiredSuccess);
+ assertNull(testEmailUpdateHandler.emailFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfSMSUpdate() throws Exception {
+ OneSignalInit();
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler);
+ assertNull(testSMSUpdateHandler.smsResult);
+ threadAndTaskWait();
+
+ assertNotNull(testSMSUpdateHandler.smsResult);
+ assertEquals(1, testSMSUpdateHandler.smsResult.length());
+ assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.get("sms_number"));
+ assertNull(testSMSUpdateHandler.smsFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfEmailEvenWhenNoChanges() throws Exception {
+ OneSignalInit();
+ String email = "josh@onesignal.com";
+ OneSignal.setEmail(email);
+ threadAndTaskWait();
+
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+ OneSignal.setEmail(email, testEmailUpdateHandler);
+ threadAndTaskWait();
+
+ assertTrue(testEmailUpdateHandler.emailFiredSuccess);
+ assertNull(testEmailUpdateHandler.emailFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfSMSEvenWhenNoChanges() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler);
+ threadAndTaskWait();
+
+ assertNotNull(testSMSUpdateHandler.smsResult);
+ assertEquals(1, testSMSUpdateHandler.smsResult.length());
+ assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.get("sms_number"));
+ assertNull(testSMSUpdateHandler.smsFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnFailureOfEmailUpdateOnNetworkFailure() throws Exception {
+ OneSignalInit();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+ OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
+ ShadowOneSignalRestClient.failAll = true;
+ threadAndTaskWait();
+
+ assertFalse(testEmailUpdateHandler.emailFiredSuccess);
+ assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType());
+ }
+
+ @Test
+ public void shouldFireOnFailureOfSMSlUpdateOnNetworkFailure() throws Exception {
+ OneSignalInit();
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler);
+ ShadowOneSignalRestClient.failAll = true;
+ threadAndTaskWait();
+
+ assertNull(testSMSUpdateHandler.smsResult);
+ assertNotNull(testSMSUpdateHandler.smsFiredFailure);
+ assertEquals(OneSignal.SMSErrorType.NETWORK, testSMSUpdateHandler.smsFiredFailure.getType());
+ }
+
+ @Test
+ public void shouldFireOnFailureOfEmailAndSMSlUpdateOnNetworkFailure() throws Exception {
+ OneSignalInit();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, testEmailUpdateHandler);
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler);
+ ShadowOneSignalRestClient.failAll = true;
+ threadAndTaskWait();
+
+ assertFalse(testEmailUpdateHandler.emailFiredSuccess);
+ assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType());
+
+ assertNull(testSMSUpdateHandler.smsResult);
+ assertNotNull(testSMSUpdateHandler.smsFiredFailure);
+ assertEquals(OneSignal.SMSErrorType.NETWORK, testSMSUpdateHandler.smsFiredFailure.getType());
+ }
+
+ @Test
+ public void shouldFireOnSuccessOnlyAfterNetworkCallAfterEmailLogout() throws Exception {
+ OneSignalInit();
+ emailSetThenLogout();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+ OneSignal.setEmail("josh@onesignal.com", testEmailUpdateHandler);
+ assertFalse(testEmailUpdateHandler.emailFiredSuccess);
+ threadAndTaskWait();
+
+ assertTrue(testEmailUpdateHandler.emailFiredSuccess);
+ assertNull(testEmailUpdateHandler.emailFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOnlyAfterNetworkCallAfterSMSLogout() throws Exception {
+ OneSignalInit();
+ smsSetThenLogout();
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler);
+ assertNull(testSMSUpdateHandler.smsResult);
+ threadAndTaskWait();
+
+ assertNotNull(testSMSUpdateHandler.smsResult);
+ assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number"));
+ assertNull(testSMSUpdateHandler.smsFiredFailure);
+ }
+
+ // Should create a new email instead of updating existing player record when no auth hash
+ @Test
+ public void shouldDoPostOnEmailChange() throws Exception {
+ OneSignalInit();
+
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533";
+ ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId;
+ String newEmail = "different@email.com";
+ OneSignal.setEmail(newEmail);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals(newEmail, emailPost.payload.get("identifier"));
+
+ ShadowOneSignalRestClient.Request playerPut = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(newMockEmailPlayerId, playerPut.payload.get("parent_player_id"));
+ }
+
+ // Should create a new sms instead of updating existing player record when no auth hash
+ @Test
+ public void shouldDoPostOnSMSChange() throws Exception {
+ OneSignalInit();
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ String newMockSMSPlayerId = "z007f967-98cc-11e4-bed1-118f05be4533";
+ ShadowOneSignalRestClient.smsUserId = newMockSMSPlayerId;
+ String newSMS = "different_sms_number";
+ OneSignal.setSMSNumber(newSMS);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(newSMS, smsPost.payload.get("identifier"));
+ }
+
+ // Should update player with new email instead of creating a new one when auth hash is provided
+ @Test
+ public void shouldUpdateEmailWhenAuthHashIsUsed() throws Exception {
+ OneSignalInit();
+ String email = "josh@onesignal.com";
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setEmail(email, mockEmailHash);
+ threadAndTaskWait();
+ OneSignal.setEmail("different@email.com", mockEmailHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request pushPut = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, pushPut.method);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", pushPut.url);
+ assertEquals("different@email.com", pushPut.payload.get("email"));
+
+ ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, emailPut.method);
+ assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522", emailPut.url);
+ assertEquals("different@email.com", emailPut.payload.get("identifier"));
+ }
+
+ // Should update player with new sms instead of creating a new one when auth hash is provided
+ @Test
+ public void shouldUpdateSMSlWhenAuthHashIsUsed() throws Exception {
+ OneSignalInit();
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockEmailHash);
+ threadAndTaskWait();
+ String newSMS = "different_sms_number";
+ OneSignal.setSMSNumber(newSMS, mockEmailHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request pushPut = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, pushPut.method);
+ assertEquals("players/" + PUSH_USER_ID, pushPut.url);
+ assertEquals(newSMS, pushPut.payload.get("sms_number"));
+
+ ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method);
+ assertEquals("players/" + SMS_USER_ID, smsPut.url);
+ assertEquals(newSMS, smsPut.payload.get("identifier"));
+ }
+
+ @Test
+ public void shouldSendEmailAuthHashWithLogout() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+ OneSignal.setEmail("josh@onesignal.com", mockEmailHash);
+ threadAndTaskWait();
+
+ OneSignal.logoutEmail();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request emailPut = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", emailPut.url);
+ assertEquals(mockEmailHash, emailPut.payload.get("email_auth_hash"));
+ }
+
+ private void emailSetThenLogout() throws Exception {
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ OneSignal.logoutEmail();
+ threadAndTaskWait();
+ }
+
+ private void smsSetThenLogout() throws Exception {
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ OneSignal.logoutSMSNumber();
+ threadAndTaskWait();
+ }
+
+ @Test
+ public void shouldLogoutOfEmail() throws Exception {
+ OneSignalInit();
+
+ emailSetThenLogout();
+
+ ShadowOneSignalRestClient.Request logoutEmailPost = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/email_logout", logoutEmailPost.url);
+ assertEquals("b007f967-98cc-11e4-bed1-118f05be4522", logoutEmailPost.payload.get("parent_player_id"));
+ assertEquals("b4f7f966-d8cc-11e4-bed1-df8f05be55ba", logoutEmailPost.payload.get("app_id"));
+ }
+
+ @Test
+ public void shouldLogoutOfSMS() throws Exception {
+ OneSignalInit();
+
+ smsSetThenLogout();
+
+ OSDeviceState deviceState = OneSignal.getDeviceState();
+ assertNull(deviceState.getSMSUserId());
+ assertNull(deviceState.getSMSNumber());
+ }
+
+ @Test
+ public void logoutEmailShouldNotSendEmailPlayersRequest() throws Exception {
+ // 1. Init OneSignal and set email
+ OneSignalInit();
+
+ emailSetThenLogout();
+
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4);
+ assertNotEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", postPush.url);
+
+ ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postEmail.url);
+ }
+
+ @Test
+ public void logoutSMSShouldNotSendSMSPlayersRequest() throws Exception {
+ // 1. Init OneSignal and set email
+ OneSignalInit();
+
+ smsSetThenLogout();
+
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertEquals(4, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(3);
+ assertNotEquals("players/" + PUSH_USER_ID, postPush.url);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfLogoutEmail() throws Exception {
+ OneSignalInit();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+ OneSignal.logoutEmail(testEmailUpdateHandler);
+ threadAndTaskWait();
+
+ assertTrue(testEmailUpdateHandler.emailFiredSuccess);
+ assertNull(testEmailUpdateHandler.emailFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnSuccessOfLogoutSMS() throws Exception {
+ OneSignalInit();
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+ OneSignal.logoutSMSNumber(testSMSUpdateHandler);
+ threadAndTaskWait();
+
+ assertNotNull(testSMSUpdateHandler.smsResult);
+ assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number"));
+ assertNull(testSMSUpdateHandler.smsFiredFailure);
+ }
+
+ @Test
+ public void shouldFireOnFailureOfLogoutEmailOnNetworkFailure() throws Exception {
+ OneSignalInit();
+ TestEmailUpdateHandler testEmailUpdateHandler = new TestEmailUpdateHandler();
+
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.logoutEmail(testEmailUpdateHandler);
+ threadAndTaskWait();
+
+ assertFalse(testEmailUpdateHandler.emailFiredSuccess);
+ assertEquals(OneSignal.EmailErrorType.NETWORK, testEmailUpdateHandler.emailFiredFailure.getType());
+ }
+
+ @Test
+ public void shouldNotFireOnFailureOfLogoutSMSOnNetworkFailure() throws Exception {
+ OneSignalInit();
+ TestSMSUpdateHandler testSMSUpdateHandler = new TestSMSUpdateHandler();
+
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.logoutSMSNumber(testSMSUpdateHandler);
+ threadAndTaskWait();
+
+ assertNotNull(testSMSUpdateHandler.smsResult);
+ assertEquals(ONESIGNAL_SMS_NUMBER, testSMSUpdateHandler.smsResult.getString("sms_number"));
+ assertNull(testSMSUpdateHandler.smsFiredFailure);
+ }
+
+ @Test
+ public void shouldCreateNewEmailAfterLogout() throws Exception {
+ OneSignalInit();
+
+ emailSetThenLogout();
+
+ String newMockEmailPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533";
+ ShadowOneSignalRestClient.emailUserId = newMockEmailPlayerId;
+ OneSignal.setEmail("different@email.com");
+ threadAndTaskWait();
+
+ // Update Push record's email field.
+ ShadowOneSignalRestClient.Request putPushEmail = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, putPushEmail.method);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511", putPushEmail.url);
+ assertEquals("different@email.com", putPushEmail.payload.get("email"));
+
+ // Create new Email record
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals("different@email.com", emailPost.payload.get("identifier"));
+
+ // Update Push record's parent_player_id
+ ShadowOneSignalRestClient.Request playerPut2 = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals(newMockEmailPlayerId, playerPut2.payload.get("parent_player_id"));
+ }
+
+ @Test
+ public void shouldCreateNewSMSAfterLogout() throws Exception {
+ OneSignalInit();
+
+ smsSetThenLogout();
+
+ String newMockSMSPlayerId = "c007f967-98cc-11e4-bed1-118f05be4533";
+ String newSMSNumber = "new_sms_number";
+
+ ShadowOneSignalRestClient.smsUserId = newMockSMSPlayerId;
+ OneSignal.setSMSNumber(newSMSNumber);
+ threadAndTaskWait();
+
+ // There should not be a parent_player_id update, last SMS POST should be the last one
+ assertEquals(5, ShadowOneSignalRestClient.requests.size());
+
+ // Update Push record's sms field.
+ ShadowOneSignalRestClient.Request putPushSMS = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, putPushSMS.method);
+ assertEquals("players/" + PUSH_USER_ID, putPushSMS.url);
+ assertEquals(newSMSNumber, putPushSMS.payload.get("sms_number"));
+
+ // Create new SMS record
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(newSMSNumber, smsPost.payload.get("identifier"));
+ }
+
+ // ####### external_id Tests ########
+
+ @Test
+ public void shouldSendExternalUserIdAfterRegistration() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+
+ OneSignal.setExternalUserId(testExternalId);
+
+ threadAndTaskWait();
+
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method);
+ assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id"));
+ }
+
+ @Test
+ public void shouldSendExternalUserIdBeforeRegistration() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ OneSignal.setExternalUserId(testExternalId);
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method);
+ assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
+ }
+
+ @Test
+ public void shouldSetExternalIdWithAuthHash() throws Exception {
+ ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(new JSONObject().put("require_user_id_auth", true));
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ assertNotNull(lastExternalUserIdError);
+ assertEquals(REQUIRES_EXTERNAL_ID_AUTH, lastExternalUserIdError.getType());
+ }
+
+ @Test
+ public void shouldSetExternalIdWithAuthHashAfterRegistration() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+ threadAndTaskWait();
+
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method);
+ assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id"));
+ assertEquals(mockExternalIdHash, externalIdRequest.payload.getString("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldSetExternalIdWithAuthHashBeforeRegistration() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method);
+ assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
+ assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldAlwaysSetExternalIdWithAuthHashAfterRegistration() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method);
+ assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
+ assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
+
+ fastColdRestartApp();
+
+ time.advanceSystemTimeBy(60);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method);
+ assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldAlwaysSetExternalIdAndEmailWithAuthHashAfterRegistration() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ String email = "josh@onesignal.com";
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ OneSignal.setEmail(email, mockEmailHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method);
+ assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
+ assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals(email, emailPost.payload.getString("identifier"));
+ assertEquals(11, emailPost.payload.getInt("device_type"));
+ assertEquals(mockEmailHash, emailPost.payload.getString("email_auth_hash"));
+
+ fastColdRestartApp();
+
+ time.advanceSystemTimeBy(60);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method);
+ assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request emailPostAfterColdStart = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPostAfterColdStart.method);
+ assertEquals(11, emailPostAfterColdStart.payload.getInt("device_type"));
+ assertEquals(mockEmailHash, emailPostAfterColdStart.payload.getString("email_auth_hash"));
+ }
+
+ @Test
+ public void shouldAlwaysSetExternalIdAndSMSWithAuthHashAfterRegistration() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ String mockSMSlHash = new String(new char[64]).replace('\0', '1');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, registrationRequest.method);
+ assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
+ assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals(ONESIGNAL_SMS_NUMBER, smsPost.payload.getString("identifier"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.getInt("device_type"));
+ assertEquals(mockSMSlHash, smsPost.payload.getString("sms_auth_hash"));
+
+ fastColdRestartApp();
+
+ time.advanceSystemTimeBy(60);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request registrationRequestAfterColdStart = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequestAfterColdStart.method);
+ assertEquals(mockExternalIdHash, registrationRequestAfterColdStart.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request smsPostAfterColdStart = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPostAfterColdStart.method);
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPostAfterColdStart.payload.getInt("device_type"));
+ assertEquals(mockSMSlHash, smsPostAfterColdStart.payload.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldSetExternalIdOnSMS() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ String mockSMSlHash = new String(new char[64]).replace('\0', '1');
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash);
+ threadAndTaskWait();
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request setExternalIdOnSMSChannel = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, setExternalIdOnSMSChannel.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, setExternalIdOnSMSChannel.url);
+ assertEquals(testExternalId, setExternalIdOnSMSChannel.payload.get("external_user_id"));
+ assertEquals(mockExternalIdHash, setExternalIdOnSMSChannel.payload.get("external_user_id_auth_hash"));
+ assertEquals(mockSMSlHash, setExternalIdOnSMSChannel.payload.get("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldSetExternalIdWithAuthHashOnSendTagsSMS() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash);
+ threadAndTaskWait();
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ threadAndTaskWait();
+
+ JSONObject tagsJson = new JSONObject("{\"test1\": \"value1\", \"test2\": \"value2\"}");
+ OneSignal.sendTags(tagsJson);
+ threadAndTaskWait();
+
+ assertEquals(7, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request smsPut = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, smsPut.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.smsUserId, smsPut.url);
+ assertEquals(4, smsPut.payload.length());
+ assertTrue(smsPut.payload.has("app_id"));
+ assertEquals(tagsJson.toString(), smsPut.payload.getJSONObject("tags").toString());
+ assertEquals(mockSMSHash, smsPut.payload.getString("sms_auth_hash"));
+ assertEquals(mockExternalIdHash, smsPut.payload.getString("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldNotSetExternalIdOnSMShWithLaterSMSNumber() throws Exception {
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ String mockSMSlHash = new String(new char[64]).replace('\0', '1');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ threadAndTaskWait();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSlHash);
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request setSMSNumberSMSChannelRequest = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, setSMSNumberSMSChannelRequest.method);
+ assertTrue(setSMSNumberSMSChannelRequest.payload.has("identifier"));
+ assertTrue(setSMSNumberSMSChannelRequest.payload.has("sms_auth_hash"));
+ assertFalse(setSMSNumberSMSChannelRequest.payload.has("external_user_id"));
+ assertFalse(setSMSNumberSMSChannelRequest.payload.has("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserId() throws Exception {
+ OneSignal.setExternalUserId("test_ext_id");
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId();
+ threadAndTaskWait();
+
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromPushWithAuthHash() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(2);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromEmailWithAuthHash() throws Exception {
+ String testEmail = "test@test.com";
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setEmail(testEmail, mockEmailHash, getEmailUpdateHandler());
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" + ", " +
+ " \"email\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ assertTrue(didEmailUpdateSucceed);
+ assertNull(lastEmailUpdateFailure);
+
+ assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertFalse(removeIdRequest.payload.has("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method);
+ assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromSMSWithAuthHash() throws Exception {
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, getSMSUpdateHandler());
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId(getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" + ", " +
+ " \"sms\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ assertNotNull(didSMSlUpdateSucceed);
+ assertNull(lastEmailUpdateFailure);
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertFalse(removeIdRequest.payload.has("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method);
+ assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromPushAndEmailWithAuthHash() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+ String testEmail = "test@test.com";
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+ OneSignal.setEmail(testEmail, mockEmailHash, null);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId();
+ threadAndTaskWait();
+
+ assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method);
+ assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromPushAndSMSWithAuthHash() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+ String mockSMSHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId();
+ threadAndTaskWait();
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method);
+ assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void shouldRemoveExternalUserIdFromPushAndEmailAndSMSWithAuthHash() throws Exception {
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+ String mockEmailHash = new String(new char[64]).replace('\0', '0');
+ String mockSMSHash = new String(new char[64]).replace('\0', '1');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS, mockEmailHash, null);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER, mockSMSHash, null);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.removeExternalUserId();
+ threadAndTaskWait();
+
+ assertEquals(8, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request removeIdRequest = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdRequest.method);
+ assertEquals(removeIdRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockExternalIdHash, removeIdRequest.payload.getString("external_user_id_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdEmailRequest = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdEmailRequest.method);
+ assertEquals(removeIdEmailRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockEmailHash, removeIdEmailRequest.payload.getString("email_auth_hash"));
+
+ ShadowOneSignalRestClient.Request removeIdSMSRequest = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, removeIdSMSRequest.method);
+ assertEquals(removeIdSMSRequest.payload.getString("external_user_id"), "");
+ assertEquals(mockSMSHash, removeIdSMSRequest.payload.getString("sms_auth_hash"));
+ }
+
+ @Test
+ public void doesNotSendSameExternalId() throws Exception {
+ String testExternalId = "test_ext_id";
+ OneSignal.setExternalUserId(testExternalId);
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
+
+ OneSignal.setExternalUserId(testExternalId);
+ threadAndTaskWait();
+
+ // Setting the same ID again should not generate a duplicate API request
+ // The SDK should detect it is the same and not generate a request
+ assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
+ }
+
+ @Test
+ public void sendsExternalIdOnEmailPlayers() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.setEmail("brad@onesignal.com");
+ threadAndTaskWait();
+
+ int currentRequestCount = ShadowOneSignalRestClient.networkCallCount;
+
+ OneSignal.setExternalUserId(testExternalId);
+ threadAndTaskWait();
+
+ // the SDK should have made two additional API calls
+ // One to set extID on the push player record,
+ // and another for the email player record
+ assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 2);
+
+ int externalIdRequests = 0;
+
+ for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) {
+ if (request.payload != null && request.payload.has("external_user_id")) {
+ externalIdRequests += 1;
+ assertEquals(request.payload.getString("external_user_id"), testExternalId);
+ }
+ }
+
+ assertEquals(externalIdRequests, 2);
+ }
+
+ @Test
+ public void sendsExternalIdOnSMSPlayers() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ int currentRequestCount = ShadowOneSignalRestClient.networkCallCount;
+
+ OneSignal.setExternalUserId(testExternalId);
+ threadAndTaskWait();
+
+ // the SDK should have made two additional API calls
+ // One to set extID on the push player record,
+ // and another for the sms player record
+ assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 2);
+
+ int externalIdRequests = 0;
+
+ for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) {
+ if (request.payload != null && request.payload.has("external_user_id")) {
+ externalIdRequests += 1;
+ assertEquals(request.payload.getString("external_user_id"), testExternalId);
+ }
+ }
+
+ assertEquals(externalIdRequests, 2);
+ }
+
+ @Test
+ public void sendsExternalIdOnEmailAndSMSPlayers() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ OneSignalInit();
+ threadAndTaskWait();
+
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ int currentRequestCount = ShadowOneSignalRestClient.networkCallCount;
+
+ OneSignal.setExternalUserId(testExternalId);
+ threadAndTaskWait();
+
+ // the SDK should have made two additional API calls
+ // One to set extID on the push player record,
+ // another for the sms player record
+ // and another for email sms player record
+ assertEquals(ShadowOneSignalRestClient.networkCallCount, currentRequestCount + 3);
+
+ int externalIdRequests = 0;
+
+ for (ShadowOneSignalRestClient.Request request : ShadowOneSignalRestClient.requests) {
+ if (request.payload != null && request.payload.has("external_user_id")) {
+ externalIdRequests += 1;
+ assertEquals(request.payload.getString("external_user_id"), testExternalId);
+ }
+ }
+
+ assertEquals(externalIdRequests, 3);
+ }
+
+ @Test
+ public void sendExternalUserId_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse is equal to the expected response
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendDifferentExternalUserId_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id_1";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse is equal to the expected response
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Change test external user id to send
+ testExternalId = "test_ext_id_2";
+
+ // 5. Attempt to set same exact external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 6. Make sure lastExternalUserIdResponse is equal to the expected response
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendSameExternalUserId_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse is equal to the expected response
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Attempt to set same exact external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 5. Make sure lastExternalUserIdResponse is equal to the expected response
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_withFailure_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback and force failure on the network requests
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse is equal to the expected response
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : false" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
+ ShadowOneSignalRestClient.failAll = false;
+
+ // 5. Attempt a second set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 6. Make sure lastExternalUserIdResponse is equal to the expected response
+ expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_forPushAndEmail_withFailure_withCompletionHandler() throws Exception {
+ String testEmail = "test@onesignal.com";
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ OneSignal.setEmail(testEmail);
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback and force failure on the network requests
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse has push and email with success : false
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : false" +
+ " }," +
+ " \"email\" : {" +
+ " \"success\" : false" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
+ ShadowOneSignalRestClient.failAll = false;
+
+ // 5. Attempt a second set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 6. Make sure lastExternalUserIdResponse has push and email with success : true
+ expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }," +
+ " \"email\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_forPushAndSMS_withFailure_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback and force failure on the network requests
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse has push and sms with success : false
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : false" +
+ " }," +
+ " \"sms\" : {" +
+ " \"success\" : false" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
+ ShadowOneSignalRestClient.failAll = false;
+
+ // 5. Attempt a second set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 6. Make sure lastExternalUserIdResponse has push and sms with success : true
+ expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }," +
+ " \"sms\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_forPushAndEmailAndSMS_withFailure_withCompletionHandler() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal
+ OneSignalInit();
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // 2. Attempt to set external user id with callback and force failure on the network requests
+ ShadowOneSignalRestClient.failAll = true;
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 3. Make sure lastExternalUserIdResponse has push and sms with success : false
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : false" +
+ " }," +
+ " \"email\" : {" +
+ " \"success\" : false" +
+ " }," +
+ " \"sms\" : {" +
+ " \"success\" : false" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+
+ // 4. Flip ShadowOneSignalRestClient.failAll flag back to false
+ ShadowOneSignalRestClient.failAll = false;
+
+ // 5. Attempt a second set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 6. Make sure lastExternalUserIdResponse has push and sms with success : true
+ expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }," +
+ " \"email\" : {" +
+ " \"success\" : true" +
+ " }," +
+ " \"sms\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_forPush_afterLoggingOutEmail_withCompletion() throws Exception {
+ String testEmail = "test@onesignal.com";
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal and set email
+ OneSignalInit();
+ OneSignal.setEmail(testEmail);
+ threadAndTaskWait();
+
+ // 2. Logout Email
+ OneSignal.logoutEmail();
+ threadAndTaskWait();
+
+ // 3. Attempt a set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 4. Make sure lastExternalUserIdResponse has push with success : true
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ @Test
+ public void sendExternalUserId_forPush_afterLoggingOutSMS_withCompletion() throws Exception {
+ String testExternalId = "test_ext_id";
+
+ // 1. Init OneSignal and set email
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ // 2. Logout SMS
+ OneSignal.logoutSMSNumber();
+ threadAndTaskWait();
+
+ // 4. Attempt a set external user id with callback
+ OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
+ threadAndTaskWait();
+
+ // 5. Make sure lastExternalUserIdResponse has push with success : true
+ JSONObject expectedExternalUserIdResponse = new JSONObject(
+ "{" +
+ " \"push\" : {" +
+ " \"success\" : true" +
+ " }" +
+ "}"
+ );
+ assertEquals(expectedExternalUserIdResponse.toString(), lastExternalUserIdResponse.toString());
+ }
+
+ // ####### on_session Tests ########
+
+ @Test
+ public void shouldSendOnSessionToEmail() throws Exception {
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ restartAppAndElapseTimeToNextSession(time);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request emailPost = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, emailPost.method);
+ assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_session", emailPost.url);
+ }
+
+ @Test
+ public void shouldSendOnSessionToSMS() throws Exception {
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ restartAppAndElapseTimeToNextSession(time);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ ShadowOneSignalRestClient.Request smsPost = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, smsPost.method);
+ assertEquals("players/" + ShadowOneSignalRestClient.SMS_USER_ID + "/on_session", smsPost.url);
+
+ // Check that the request only has app_id, device_type and device_player_id
+ assertEquals(3, smsPost.payload.length());
+ assertEquals(PUSH_USER_ID, smsPost.payload.get("device_player_id"));
+ assertEquals(OneSignalPackagePrivateHelper.UserState.DEVICE_TYPE_SMS, smsPost.payload.get("device_type"));
+ assertTrue(smsPost.payload.has("app_id"));
+ }
+
+ // ####### on_focus Tests ########
+
+ @Test
+ public void sendsOnFocus() throws Exception {
+ time.advanceSystemAndElapsedTimeBy(0);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertOnFocusAtIndex(2, 60);
+ assertRestCalls(3);
+ }
+
+ @Test
+ public void sendsOnFocusWithExternalId() throws Exception {
+ time.advanceSystemAndElapsedTimeBy(0);
+ OneSignalInit();
+ threadAndTaskWait();
+
+ String testExternalId = "test_ext_id";
+ String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
+
+ OneSignal.setExternalUserId(testExternalId, mockExternalIdHash);
+ threadAndTaskWait();
+
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertOnFocusAtIndex(3, 60);
+ assertRestCalls(4);
+ assertFalse(ShadowOneSignalRestClient.lastPost.has("external_user_id"));
+ assertFalse(ShadowOneSignalRestClient.lastPost.has("external_user_id_auth_hash"));
+ }
+
+ @Test
+ public void sendsOnFocusToEmail() throws Exception {
+ time.advanceSystemAndElapsedTimeBy(0);
+ OneSignalInit();
+ OneSignal.setEmail("josh@onesignal.com");
+ threadAndTaskWait();
+
+ blankActivityController.resume();
+ threadAndTaskWait();
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertEquals(6, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(3);
+ assertFalse(post.url.contains("on_focus"));
+
+ ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postPush.url);
+ assertEquals(60, postPush.payload.getInt("active_time"));
+
+ ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals("players/b007f967-98cc-11e4-bed1-118f05be4522/on_focus", postEmail.url);
+ assertEquals(60, postEmail.payload.getInt("active_time"));
+ }
+
+ @Test
+ public void sendsOnFocusToSMS() throws Exception {
+ time.advanceSystemAndElapsedTimeBy(0);
+ OneSignalInit();
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ blankActivityController.resume();
+ threadAndTaskWait();
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertEquals(5, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(2);
+ assertFalse(post.url.contains("on_focus"));
+
+ ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(3);
+ assertEquals("players/a2f7f967-e8cc-11e4-bed1-118f05be4511/on_focus", postPush.url);
+ assertEquals(60, postPush.payload.getInt("active_time"));
+
+ ShadowOneSignalRestClient.Request postSMSl = ShadowOneSignalRestClient.requests.get(4);
+ assertEquals("players/" + SMS_USER_ID + "/on_focus", postSMSl.url);
+ assertEquals(60, postSMSl.payload.getInt("active_time"));
+ }
+
+ @Test
+ public void sendsOnFocusToEmailAndSMS() throws Exception {
+ time.advanceSystemAndElapsedTimeBy(0);
+ OneSignalInit();
+ OneSignal.setEmail(ONESIGNAL_EMAIL_ADDRESS);
+ OneSignal.setSMSNumber(ONESIGNAL_SMS_NUMBER);
+ threadAndTaskWait();
+
+ blankActivityController.resume();
+ threadAndTaskWait();
+ time.advanceSystemAndElapsedTimeBy(60);
+ pauseActivity(blankActivityController);
+ assertAndRunSyncService();
+
+ assertEquals(8, ShadowOneSignalRestClient.networkCallCount);
+
+ ShadowOneSignalRestClient.Request post = ShadowOneSignalRestClient.requests.get(4);
+ assertFalse(post.url.contains("on_focus"));
+
+ ShadowOneSignalRestClient.Request postPush = ShadowOneSignalRestClient.requests.get(5);
+ assertEquals("players/" + PUSH_USER_ID + "/on_focus", postPush.url);
+ assertEquals(60, postPush.payload.getInt("active_time"));
+
+ ShadowOneSignalRestClient.Request postEmail = ShadowOneSignalRestClient.requests.get(6);
+ assertEquals("players/" + EMAIL_USER_ID + "/on_focus", postEmail.url);
+ assertEquals(60, postEmail.payload.getInt("active_time"));
+
+ ShadowOneSignalRestClient.Request postSMSl = ShadowOneSignalRestClient.requests.get(7);
+ assertEquals("players/" + SMS_USER_ID + "/on_focus", postSMSl.url);
+ assertEquals(60, postSMSl.payload.getInt("active_time"));
+ }
+
+ private void OneSignalInit() {
+ OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
+ ShadowOSUtils.subscribableStatus = 1;
+ OneSignal_setTime(time);
+ OneSignal_setTrackerFactory(trackerFactory);
+ OneSignal_setSessionManager(sessionManager);
+ OneSignal.setAppId(ONESIGNAL_APP_ID);
+ OneSignal.initWithContext(blankActivity);
+ blankActivityController.resume();
+ }
+}