Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getter for onesignalId and UserStateObserver #1909

Merged
merged 5 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
import com.onesignal.sdktest.constant.Text;
import com.onesignal.sdktest.notification.OneSignalNotificationSender;
import com.onesignal.sdktest.util.SharedPreferenceUtil;
import com.onesignal.user.IUserStateObserver;
import com.onesignal.user.UserChangedState;
import com.onesignal.user.UserState;

import org.json.JSONObject;

Expand Down Expand Up @@ -116,6 +119,14 @@ public void onWillDisplay(@NonNull INotificationWillDisplayEvent event) {
}
});

OneSignal.getUser().addObserver(new IUserStateObserver() {
@Override
public void onUserStateChange(@NonNull UserChangedState state) {
UserState currentUserState = state.getCurrent();
Log.v(Tag.LOG_TAG, "onUserStateChange fired " + currentUserState.toJSONObject());
}
});

OneSignal.getInAppMessages().setPaused(true);
OneSignal.getLocation().setShared(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import android.app.Activity;
import android.content.Context;
import com.google.android.material.appbar.AppBarLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
Expand All @@ -13,10 +12,8 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.appcompat.widget.Toolbar;

import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.view.ViewTreeObserver;
Expand All @@ -25,13 +22,10 @@
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;

import com.onesignal.Continue;
import com.onesignal.OneSignal;
import com.onesignal.sdktest.adapter.SubscriptionRecyclerViewAdapter;
import com.onesignal.user.subscriptions.IEmailSubscription;
import com.onesignal.user.subscriptions.IPushSubscription;
import com.onesignal.user.subscriptions.ISmsSubscription;
import com.onesignal.sdktest.R;
import com.onesignal.sdktest.activity.SecondaryActivity;
import com.onesignal.sdktest.adapter.InAppMessageRecyclerViewAdapter;
Expand All @@ -57,7 +51,6 @@
import com.onesignal.user.subscriptions.ISubscription;
import com.onesignal.user.subscriptions.IPushSubscriptionObserver;
import com.onesignal.user.subscriptions.PushSubscriptionChangedState;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ interface IUserManager {
*/
val pushSubscription: IPushSubscription

/**
* onesignalId, null if this is current unavailable
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
*/
val onesignalId: String

/**
* externalId, null if this is current unavailable
*/
val externalId: String

/**
* Set the 2-character language either as a detected language or explicitly set for this user. See
* See [Supported Languages | OneSignal](https://documentation.onesignal.com/docs/language-localization#what-languages-are-supported)
Expand Down Expand Up @@ -138,4 +148,15 @@ interface IUserManager {
* Return a copy of all local tags from the current user.
*/
fun getTags(): Map<String, String>

/**
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
* Add an observer to the user state, allowing the provider to be
* notified whenever the user state has changed.
*/
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
fun addObserver(observer: IUserStateObserver)

/**
* Remove an observer from the user state.
*/
fun removeObserver(observer: IUserStateObserver)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.onesignal.user
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved

/**
* A user state changed handler. Implement this interface and provide the implementation
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
* to be notified when the user has changed.
*/
interface IUserStateObserver {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call out somewhere in the KDoc that app developers should be checking both the onesignalId and the externalId in the UserState to make sure they are grabbing the correct onesignalId.

For example, a new app install that calls login("ext1") will trigger the callback twice. App developers may just grab the very first callback and save the onesignalId. However, that first callback will contain an "" externalId, and it is the second callback that contains the actual onesignalId they want and an externalId of ext1.

I'm not sure where best to put this information since it can go in the description of IUserStateObserver or fun onUserStateChange, UserChangedState, or UserState.

I need to do the equivalent for iOS as well.

/**
* Called when the user state this change handler was added to, has changed. A
* user state can change when user has logged in or out
*
* @param state The user changed state.
*/
fun onUserStateChange(state: UserChangedState)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.onesignal.user

import org.json.JSONObject

class UserChangedState(
val current: UserState,
) {
fun toJSONObject(): JSONObject {
return JSONObject()
.put("current", current.toJSONObject())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.onesignal.user

import org.json.JSONObject

/**
* A user state.
*/
class UserState(
/**
* The unique identifier for your OneSignal account. This will be an empty string until the
* user has been successfully logged in on the backend and assigned an ID.
* Use [addObserver] to be notified when the [onesignalId] has been successfully assigned.
*/
val onesignalId: String,
/**
* The external identifier that you use to identify users. This will be an empty string
* until the user has been successfully logged in on the backend and assigned an ID.
* Use [addObserver] to be notified when the [externalId] has
* been successfully assigned.
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
*/
val externalId: String,
) {
fun toJSONObject(): JSONObject {
return JSONObject()
.put("onesignalId", onesignalId)
.put("externalId", externalId)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.onesignal.user.internal

import com.onesignal.common.IDManager
import com.onesignal.common.OneSignalUtils
import com.onesignal.common.events.EventProducer
import com.onesignal.common.modeling.ISingletonModelStoreChangeHandler
import com.onesignal.common.modeling.ModelChangedArgs
import com.onesignal.core.internal.language.ILanguageContext
import com.onesignal.debug.LogLevel
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.user.IUserManager
import com.onesignal.user.IUserStateObserver
import com.onesignal.user.UserChangedState
import com.onesignal.user.UserState
import com.onesignal.user.internal.backend.IdentityConstants
import com.onesignal.user.internal.identity.IdentityModel
import com.onesignal.user.internal.identity.IdentityModelStore
Expand All @@ -19,16 +26,21 @@ internal open class UserManager(
private val _identityModelStore: IdentityModelStore,
private val _propertiesModelStore: PropertiesModelStore,
private val _languageContext: ILanguageContext,
) : IUserManager {
val externalId: String?
get() = _identityModel.externalId
) : IUserManager, ISingletonModelStoreChangeHandler<IdentityModel> {
override val onesignalId: String
get() = if (IDManager.isLocalId(_identityModel.onesignalId)) "" else _identityModel.onesignalId

override val externalId: String
get() = _identityModel.externalId ?: ""

val aliases: Map<String, String>
get() = _identityModel.filter { it.key != IdentityModel::id.name }.toMap()

val subscriptions: SubscriptionList
get() = _subscriptionManager.subscriptions

val changeHandlersNotifier = EventProducer<IUserStateObserver>()

override val pushSubscription: IPushSubscription
get() = _subscriptionManager.subscriptions.push

Expand All @@ -42,6 +54,10 @@ internal open class UserManager(
_languageContext.language = value
}

init {
_identityModelStore.subscribe(this)
}

override fun addAlias(
label: String,
id: String,
Expand Down Expand Up @@ -219,4 +235,30 @@ internal open class UserManager(
override fun getTags(): Map<String, String> {
return _propertiesModel.tags.toMap()
}

override fun addObserver(observer: IUserStateObserver) {
changeHandlersNotifier.subscribe(observer)
}

override fun removeObserver(observer: IUserStateObserver) {
changeHandlersNotifier.unsubscribe(observer)
}

override fun onModelReplaced(
model: IdentityModel,
tag: String,
) { }

override fun onModelUpdated(
args: ModelChangedArgs,
tag: String,
) {
if (args.property == IdentityConstants.ONESIGNAL_ID) {
val newUserState = UserState(args.newValue.toString(), externalId)
this.changeHandlersNotifier.fire {
it.onUserStateChange(UserChangedState(newUserState))
}
}
Logging.debug(args.property)
jinliu9508 marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ object MockHelper {
action(identityModel)
}

val mockIdentityStore = mockk<IdentityModelStore>()
val mockIdentityStore = mockk<IdentityModelStore>(relaxed = true)

every { mockIdentityStore.model } returns identityModel

Expand Down
4 changes: 4 additions & 0 deletions OneSignalSDK/onesignal/notifications/consumer-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
void onPushSubscriptionChange(com.onesignal.user.subscriptions.PushSubscriptionChangedState);
}

-keep class ** implements com.onesignal.user.IUserStateObserver {
void onUserStateChange(com.onesignal.user.UserChangedState);
}

-keep class ** implements com.onesignal.notifications.INotificationServiceExtension{
void onNotificationReceived(com.onesignal.notifications.INotificationReceivedEvent);
}
Expand Down
Loading