![JAR search and dependency download from the Maven repository](/logo.png)
co.easimart.EasimartPush Maven / Gradle / Ivy
package co.easimart;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import bolts.Continuation;
import bolts.Task;
/**
* The {@code EasimartPush} is a local representation of data that can be sent as a push notification.
*
* The typical workflow for sending a push notification from the client is to construct a new
* {@code EasimartPush}, use the setter functions to fill it with data, and then use
* {@link #sendInBackground()} to send it.
*/
public class EasimartPush {
/* package for test */ static String KEY_DATA_MESSAGE = "alert";
/* package for test */ static EasimartPushController getPushController() {
return EasimartCorePlugins.getInstance().getPushController();
}
/* package for test */ static EasimartPushChannelsController getPushChannelsController() {
return EasimartCorePlugins.getInstance().getPushChannelsController();
}
private static void checkArgument(boolean expression, Object errorMessage) {
if (!expression) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
}
/* package */ static class State {
/* package */ static class Builder {
private Set channelSet;
private EasimartQuery query;
private Long expirationTime;
private Long expirationTimeInterval;
private Boolean pushToIOS;
private Boolean pushToAndroid;
private JSONObject data;
public Builder expirationTime(Long expirationTime) {
this.expirationTime = expirationTime;
expirationTimeInterval = null;
return this;
}
public Builder expirationTimeInterval(Long expirationTimeInterval) {
this.expirationTimeInterval = expirationTimeInterval;
expirationTime = null;
return this;
}
public Builder pushToIOS(Boolean pushToIOS) {
checkArgument(query == null, "Cannot set push targets (i.e. setPushToAndroid or " +
"setPushToIOS) when pushing to a query");
this.pushToIOS = pushToIOS;
return this;
}
public Builder pushToAndroid(Boolean pushToAndroid) {
checkArgument(query == null, "Cannot set push targets (i.e. setPushToAndroid or " +
"setPushToIOS) when pushing to a query");
this.pushToAndroid = pushToAndroid;
return this;
}
public Builder data(JSONObject data) {
this.data = data;
return this;
}
public Builder channelSet(Collection channelSet) {
checkArgument(channelSet != null, "channels collection cannot be null");
for (String channel : channelSet) {
checkArgument(channel != null, "channel cannot be null");
}
this.channelSet = new HashSet<>(channelSet);
query = null;
return this;
}
public Builder query(EasimartQuery query) {
checkArgument(query != null, "Cannot target a null query");
checkArgument(pushToIOS == null && pushToAndroid == null, "Cannot set push targets " +
"(i.e. setPushToAndroid or setPushToIOS) when pushing to a query");
checkArgument(
query.getClassName().equals(EasimartObject.getClassName(EasimartInstallation.class)),
"Can only push to a query for Installations");
channelSet = null;
this.query = query;
return this;
}
public State build() {
if (data == null) {
throw new IllegalArgumentException(
"Cannot send a push without calling either setMessage or setData");
}
return new State(this);
}
}
private final Set channelSet;
private final EasimartQuery.State queryState;
private final Long expirationTime;
private final Long expirationTimeInterval;
private final Boolean pushToIOS;
private final Boolean pushToAndroid;
private final JSONObject data;
private State(Builder builder) {
this.channelSet = builder.channelSet == null ?
null : Collections.unmodifiableSet(new HashSet<>(builder.channelSet));
this.queryState = builder.query == null ? null : builder.query.getBuilder().build();
this.expirationTime = builder.expirationTime;
this.expirationTimeInterval = builder.expirationTimeInterval;
this.pushToIOS = builder.pushToIOS;
this.pushToAndroid = builder.pushToAndroid;
// Since in builder.build() we check data is not null, we do not need to check it again here.
JSONObject copyData = null;
try {
copyData = new JSONObject(builder.data.toString());
} catch (JSONException e) {
// Swallow this silently since it is impossible to happen
}
this.data = copyData;
}
public Set channelSet() {
return channelSet;
}
public EasimartQuery.State queryState() {
return queryState;
}
public Long expirationTime() {
return expirationTime;
}
public Long expirationTimeInterval() {
return expirationTimeInterval;
}
public Boolean pushToIOS() {
return pushToIOS;
}
public Boolean pushToAndroid() {
return pushToAndroid;
}
public JSONObject data() {
// Since in builder.build() we check data is not null, we do not need to check it again here.
JSONObject copyData = null;
try {
copyData = new JSONObject(data.toString());
} catch (JSONException e) {
// Swallow this exception silently since it is impossible to happen
}
return copyData;
}
}
private static final String TAG = "co.easimart.EasimartPush";
/* package for test */ final State.Builder builder;
/**
* Creates a new push notification. The default channel is the empty string, also known as the
* global broadcast channel, but this value can be overridden using {@link #setChannel(String)},
* {@link #setChannels(Collection)} or {@link #setQuery(EasimartQuery)}. Before sending the push
* notification you must call either {@link #setMessage(String)} or {@link #setData(JSONObject)}.
*/
public EasimartPush() {
this(new State.Builder());
}
private EasimartPush(State.Builder builder) {
this.builder = builder;
}
/**
* Adds 'channel' to the 'channels' list in the current {@link EasimartInstallation} and saves it in
* a background thread.
*
* @param channel
* The channel to subscribe to.
* @return A Task that is resolved when the the subscription is complete.
*/
public static Task subscribeInBackground(String channel) {
return getPushChannelsController().subscribeInBackground(channel);
}
/**
* Adds 'channel' to the 'channels' list in the current {@link EasimartInstallation} and saves it in
* a background thread.
*
* @param channel
* The channel to subscribe to.
* @param callback
* The SaveCallback that is called after the Installation is saved.
*/
public static void subscribeInBackground(String channel, SaveCallback callback) {
EasimartTaskUtils.callbackOnMainThreadAsync(subscribeInBackground(channel), callback);
}
/**
* Removes 'channel' from the 'channels' list in the current {@link EasimartInstallation} and saves
* it in a background thread.
*
* @param channel
* The channel to unsubscribe from.
* @return A Task that is resolved when the the unsubscription is complete.
*/
public static Task unsubscribeInBackground(String channel) {
return getPushChannelsController().unsubscribeInBackground(channel);
}
/**
* Removes 'channel' from the 'channels' list in the current {@link EasimartInstallation} and saves
* it in a background thread.
*
* @param channel
* The channel to unsubscribe from.
* @param callback
* The SaveCallback that is called after the Installation is saved.
*/
public static void unsubscribeInBackground(String channel, SaveCallback callback) {
EasimartTaskUtils.callbackOnMainThreadAsync(unsubscribeInBackground(channel), callback);
}
/**
* A helper method to concisely send a push message to a query. This method is equivalent to
* EasimartPush push = new EasimartPush(); push.setMessage(message); push.setQuery(query);
* push.sendInBackground();
*
* @param message
* The message that will be shown in the notification.
* @param query
* A EasimartInstallation query which specifies the recipients of a push.
* @return A task that is resolved when the message is sent.
*/
public static Task sendMessageInBackground(String message,
EasimartQuery query) {
EasimartPush push = new EasimartPush();
push.setQuery(query);
push.setMessage(message);
return push.sendInBackground();
}
/**
* A helper method to concisely send a push message to a query. This method is equivalent to
* EasimartPush push = new EasimartPush(); push.setMessage(message); push.setQuery(query);
* push.sendInBackground(callback);
*
* @param message
* The message that will be shown in the notification.
* @param query
* A EasimartInstallation query which specifies the recipients of a push.
* @param callback
* callback.done(e) is called when the send completes.
*/
public static void sendMessageInBackground(String message, EasimartQuery query,
SendCallback callback) {
EasimartTaskUtils.callbackOnMainThreadAsync(sendMessageInBackground(message, query), callback);
}
/**
* A helper method to concisely send a push to a query. This method is equivalent to EasimartPush
* push = new EasimartPush(); push.setData(data); push.setQuery(query); push.sendInBackground();
*
* @param data
* The entire data of the push message. See the push guide for more details on the data
* format.
* @param query
* A EasimartInstallation query which specifies the recipients of a push.
* @return A task that is resolved when the data is sent.
*/
public static Task sendDataInBackground(JSONObject data,
EasimartQuery query) {
EasimartPush push = new EasimartPush();
push.setQuery(query);
push.setData(data);
return push.sendInBackground();
}
/**
* A helper method to concisely send a push to a query. This method is equivalent to EasimartPush
* push = new EasimartPush(); push.setData(data); push.setQuery(query);
* push.sendInBackground(callback);
*
* @param data
* The entire data of the push message. See the push guide for more details on the data
* format.
* @param query
* A EasimartInstallation query which specifies the recipients of a push.
* @param callback
* callback.done(e) is called when the send completes.
*/
public static void sendDataInBackground(JSONObject data, EasimartQuery query,
SendCallback callback) {
EasimartTaskUtils.callbackOnMainThreadAsync(sendDataInBackground(data, query), callback);
}
/**
* Sets the channel on which this push notification will be sent. The channel name must start with
* a letter and contain only letters, numbers, dashes, and underscores. A push can either have
* channels or a query. Setting this will unset the query.
*/
public void setChannel(String channel) {
builder.channelSet(Collections.singletonList(channel));
}
/**
* Sets the collection of channels on which this push notification will be sent. Each channel name
* must start with a letter and contain only letters, numbers, dashes, and underscores. A push can
* either have channels or a query. Setting this will unset the query.
*/
public void setChannels(Collection channels) {
builder.channelSet(channels);
}
/**
* Sets the query for this push for which this push notification will be sent. This query will be
* executed in the Easimart cloud; this push notification will be sent to Installations which this
* query yields. A push can either have channels or a query. Setting this will unset the channels.
*
* @param query
* A query to which this push should target. This must be a EasimartInstallation query.
*/
public void setQuery(EasimartQuery query) {
builder.query(query);
}
/**
* Sets a UNIX epoch timestamp at which this notification should expire, in seconds (UTC). This
* notification will be sent to devices which are either online at the time the notification is
* sent, or which come online before the expiration time is reached. Because device clocks are not
* guaranteed to be accurate, most applications should instead use
* {@link #setExpirationTimeInterval(long)}.
*/
public void setExpirationTime(long time) {
builder.expirationTime(time);
}
/**
* Sets the time interval after which this notification should expire, in seconds. This
* notification will be sent to devices which are either online at the time the notification is
* sent, or which come online within the given number of seconds of the notification being
* received by Easimart's server. An interval which is less than or equal to zero indicates that the
* message should only be sent to devices which are currently online.
*/
public void setExpirationTimeInterval(long timeInterval) {
builder.expirationTimeInterval(timeInterval);
}
/**
* Clears both expiration values, indicating that the notification should never expire.
*/
public void clearExpiration() {
builder.expirationTime(null);
builder.expirationTimeInterval(null);
}
/**
* Set whether this push notification will go to iOS devices.
*
* Setting this to {@code true} will set {@link #setPushToAndroid(boolean)} to {@code false}.
*
* Note: You must set up iOS push certificates before sending pushes to iOS.
*
* @deprecated Please use {@link #setQuery(EasimartQuery)} with a {@link EasimartQuery} targeting
* {@link EasimartInstallation}s with a constraint on the {@code deviceType} field. If you use
* {@code #setPushToIOS(boolean)} or {@link #setPushToAndroid(boolean)}, then you will only be
* able to send to one of these two device types (e.g. and not Windows).
*/
@Deprecated
public void setPushToIOS(boolean pushToIOS) {
builder.pushToIOS(pushToIOS);
}
/**
* Set whether this push notification will go to Android devices.
*
* Setting this to {@code true} will set {@link #setPushToIOS(boolean)} to {@code false}.
*
* @deprecated Please use {@link #setQuery(EasimartQuery)} with a {@link EasimartQuery} targeting
* {@link EasimartInstallation}s with a constraint on the {@code deviceType} field. If you use
* {@code #setPushToAndroid(boolean)} or {@link #setPushToIOS(boolean)}, then you will only be
* able to send to one of these two device types (e.g. and not Windows).
*/
@Deprecated
public void setPushToAndroid(boolean pushToAndroid) {
builder.pushToAndroid(pushToAndroid);
}
/**
* Sets the entire data of the push message. See the push guide for more details on the data
* format. This will overwrite any data specified in {@link #setMessage(String)}.
*/
public void setData(JSONObject data) {
builder.data(data);
}
/**
* Sets the message that will be shown in the notification. This will overwrite any data specified
* in {@link #setData(JSONObject)}.
*/
public void setMessage(String message) {
JSONObject data = new JSONObject();
try {
data.put(KEY_DATA_MESSAGE, message);
} catch (JSONException e) {
EasimartLog.e(TAG, "JSONException in setMessage", e);
}
setData(data);
}
/**
* Sends this push notification in a background thread. Use this when you do not have code to run
* on completion of the push.
*
* @return A Task is resolved when the push has been sent.
*/
public Task sendInBackground() {
// Since getCurrentSessionTokenAsync takes time, we build the state before it.
final State state = builder.build();
return EasimartUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() {
@Override
public Task then(Task task) throws Exception {
String sessionToken = task.getResult();
return getPushController().sendInBackground(state, sessionToken);
}
});
}
/**
* Sends this push notification while blocking this thread until the push notification has
* successfully reached the Easimart servers. Typically, you should use {@link #sendInBackground()}
* instead of this, unless you are managing your own threading.
*
* @throws EasimartException
* Throws an exception if the server is inaccessible.
*/
public void send() throws EasimartException {
EasimartTaskUtils.wait(sendInBackground());
}
/**
* Sends this push notification in a background thread. This is preferable to using
* send()
, unless your code is already running from a background thread.
*
* @param callback
* callback.done(e) is called when the send completes.
*/
public void sendInBackground(SendCallback callback) {
EasimartTaskUtils.callbackOnMainThreadAsync(sendInBackground(), callback);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy