Skip to content

Instantly share code, notes, and snippets.

@ubarua123
Last active February 16, 2016 19:14
Show Gist options
  • Save ubarua123/db8f51905de0b87d359a to your computer and use it in GitHub Desktop.
Save ubarua123/db8f51905de0b87d359a to your computer and use it in GitHub Desktop.
Helper class to create notifications
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Action;
import android.support.v4.app.NotificationCompat.BigTextStyle;
import android.support.v4.app.NotificationCompat.InboxStyle;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
import android.widget.RemoteViews;
import java.lang.ref.WeakReference;
/**
* Use this class to help create and post notifications on the Android System.<br/>
* This class uses a "re-builder" as a wrapper to the already existing {@linkplain NotificationCompat.Builder}.
* It provides a simpler way to add options and create a notification object. As an example:
* <pre>
* A typical notification code would look like this:<br/>
* NotificationCompat.Builder notificationBuilder =
* new NotificationCompat.Builder(mContext)
* .setSmallIcon(R.mipmap.ic_app_logo_monochrome)
* .setLargeIcon(largeIcon)
* .setContentTitle(title)
* .setTicker("This is a test")
* .setContentText(content)
* .setAutoCancel(true);
*
* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
* notificationBuilder.setColor(ContextCompat.getColor(mContext, R.color.red));
* }
*
* // Specify the sound file
* Uri fileUri = Uri.parse("android.resource://"
* + mContext.getPackageName()
* + "/raw/" ..... etc etc
* .
* .
* .
* Other if else cases
*
*
* Using this class it becomes:
*
* NotificationHelper helper =
* new NotificationHelper.Builder(mContext)
* .setContentText(content)
* .setTitleText(title)
* .setTickerText(tickerText)
* .setLargeIcon(largeIcon)
* .setAutoCancel(true)
* .setIsSticky(false)
* .playSound(true, R.raw.filename)
* .setVibrate(true)
* .setCustomLayout(new RemoteViews(mContext.getPackageName(), R.layout.some_layout))
* .create();
* helper.postNotification();
*
*
* </pre>
*
* @author Udayaditya Barua. 16/2/16
* @see Builder
*/
public final class NotificationHelper {
private Notification mNotification;
private NotificationManager mNotificationManager;
private WeakReference<Context> mContextWeak;
private NotificationHelper(Notification notification, NotificationManager manager, Context context) {
mNotification = notification;
mNotificationManager = manager;
mContextWeak = new WeakReference<>(context);
}
/**
* Wrapper builder class used in helping construct a
* {@linkplain NotificationCompat.Builder} object.
* It accepts more parameters than the compat class and can be
* used to add flags in the final {@linkplain Notification} object.<br/>
* Takes care of a lot of boiler plate code which usually require conditional
* building of the compat builder. Also some of the options are of the {@linkplain Notification} object itself.
* This builder takes care of that too.
*/
public static class Builder {
private final Context mContext;
private boolean mIsSticky = false;
private boolean mIsVibrate = false;
private boolean mIsAutoCancel = false;
private boolean mPlaySound = false;
private boolean mProgressIndeterminate = false;
private boolean mShowProgress = false;
private String mContentText;
private String mTitleText;
private String mTickerText;
private Action mFirstAction;
private Action mSecondAction;
private Action mThirdAction;
private int mSoundRaw;
private int mMaxVal;
private int mCurrProgress;
private Bitmap mLargeIcon;
private BigTextStyle mBigContent;
private RemoteViews mCustomView;
private InboxStyle mInboxStyle;
private int mSmallIcon;
private int mSmallIconBgColor;
/**
* Constructor for {@linkplain Builder}
*
* @param context
* valid context
*/
public Builder(@NonNull Context context) {
mContext = context;
}
/**
* Set whether this notification should get removed or not when the user swipes or
* taps "Clear"
*
* @param isSticky
* true for yes make it "sticky" false for no
* @return {@linkplain Builder}
*/
public Builder setIsSticky(boolean isSticky) {
mIsSticky = isSticky;
return this;
}
public Builder setVibrate(boolean vibrate) {
mIsVibrate = vibrate;
return this;
}
public Builder playSound(boolean playSound, int soundRaw) {
mPlaySound = playSound;
mSoundRaw = soundRaw;
return this;
}
public Builder setContentText(@NonNull String contentText) {
mContentText = contentText;
return this;
}
public Builder setTitleText(@NonNull String title) {
mTitleText = title;
return this;
}
public Builder setTickerText(@NonNull String tickerText) {
mTickerText = tickerText;
return this;
}
public Builder setLargeIcon(@NonNull Bitmap largeIcon) {
mLargeIcon = largeIcon;
return this;
}
public Builder setSmallIcon(@DrawableRes int smallIcon) {
mSmallIcon = smallIcon;
return this;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public Builder setSmallIcon(@DrawableRes int smallIcon, @ColorRes int bgColor) {
mSmallIcon = smallIcon;
mSmallIconBgColor = bgColor;
return this;
}
/**
* Set if you want the notification to disappear the moment user taps on it.<br/>
*
* @param autoCancel
* @return
*/
public Builder setAutoCancel(boolean autoCancel) {
mIsAutoCancel = autoCancel;
return this;
}
public Builder addFirstAction(Action action) {
mFirstAction = action;
return this;
}
public Builder addSecondAction(Action action) {
mSecondAction = action;
return this;
}
public Builder addThirdAction(Action action) {
mThirdAction = action;
return this;
}
public Builder setBigText(BigTextStyle bigContent) {
mBigContent = bigContent;
return this;
}
public Builder setInboxStyleList(InboxStyle inboxStyle) {
mInboxStyle = inboxStyle;
return this;
}
/**
* Set a progrss bar to be shown.
*
* @param showProgress
* @param max
* @param curProgress
* @param isIndeterminate
* @return
*/
public Builder setProgress(boolean showProgress, int max, int curProgress, boolean isIndeterminate) {
mShowProgress = showProgress;
mMaxVal = max;
mCurrProgress = curProgress;
mProgressIndeterminate = isIndeterminate;
return this;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Builder setCustomLayout(RemoteViews remoteViews) {
mCustomView = remoteViews;
return this;
}
/**
* Create the notification object using the parameters passed.
*
* @return
*/
public NotificationHelper create() {
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(mContext)
.setLargeIcon(mLargeIcon)
.setContentTitle(mTitleText)
.setTicker(mTickerText)
.setContentText(mContentText)
.setAutoCancel(mIsAutoCancel);
if (mSmallIcon > 0)
notificationBuilder.setSmallIcon(mSmallIcon);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mSmallIconBgColor > 0) {
int resolvedColor = ContextCompat.getColor(mContext, mSmallIconBgColor);
notificationBuilder.setColor(resolvedColor);
}
}
if (mPlaySound) {
// Specify the sound file
Uri fileUri = Uri.parse("android.resource://"
+ mContext.getPackageName()
+ "/raw/"
+ mSoundRaw);
notificationBuilder.setSound(fileUri);
}
if (mBigContent != null && mInboxStyle != null) {
throw new IllegalArgumentException("Cannot set both Inbox and BigText styles simultaneiously. Only 1 is permitted");
}
// Set the big text style
if (mBigContent != null) {
notificationBuilder.setStyle(mBigContent);
}
// Set the inbox style
if (mInboxStyle != null)
notificationBuilder.setStyle(mInboxStyle);
// Set if it has to vibrate
if (mIsVibrate) {
notificationBuilder.setVibrate(new long[]{1000, 1000});
}
// Whether this is a progress notifcation
if (mShowProgress) {
notificationBuilder.setProgress(mMaxVal, mCurrProgress, mProgressIndeterminate);
}
/* Add the actions */
if (mFirstAction != null)
notificationBuilder.addAction(mFirstAction);
if (mSecondAction != null)
notificationBuilder.addAction(mSecondAction);
if (mThirdAction != null)
notificationBuilder.addAction(mThirdAction);
notificationBuilder.setShowWhen(true);
// Get the manager
NotificationManager manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
// Get the notification object
Notification notification = notificationBuilder.build();
if (mIsSticky) {
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
}
if (mCustomView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
notification.bigContentView = mCustomView;
return new NotificationHelper(notification, manager, mContext);
}
public Context getContext() {
return mContext;
}
}
/**
* Post a notification using the notification created using
* the {@linkplain Builder} and it uses an incremental style
* of managing the IDs. If you want to notify using a particular ID, then call
* {@linkplain NotificationHelper#postNotification(int)}
*/
public void postNotification() {
if (mNotification != null && mNotificationManager != null && mContextWeak.get() != null) {
mNotificationManager.notify(SharedprefClass.getNextNotificationId(mContextWeak.get()), mNotification);
}
}
/**
* Post a notification using an ID provided instead of the usual incremental ID.
* This method depends on the notifiction being created using {@linkplain Builder}.<br/>
* Possible example to use this type is showing a progress bar which will need regular updates to the
* same notification hence will use the same id.
* <h2>Warning:</h2> Take care of the ID that you're passing as it might override an existing one
*
* @param id
* unique id
*/
public void postNotification(int id) {
if (mNotification != null && mNotificationManager != null) {
mNotificationManager.notify(id, mNotification);
}
}
public Notification getNotification() {
return mNotification;
}
public NotificationManager getNotificationManager() {
return mNotificationManager;
}
}
public class SharedprefClass {
private static final String NOTIFICATION_ID = "notif_id";
/**
* Gets a new ID to be used for the notification.notify call.
* @param context
* @return
*/
public static int getNextNotificationId(final Context context) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
int currId = sharedPreferences.getInt(NOTIFICATION_ID, 0);
int nextId = currId + 1;
if (nextId >= 1000) {// Capping it to 1000. Reset here
nextId = 1;
}
// Store this
storeCurrNotificationId(context, nextId);
return nextId;
}
@SuppressLint("CommitPrefEdits")
public static void storeCurrNotificationId(final Context context, int id) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
Editor editor = sharedPreferences.edit();
editor.putInt(NOTIFICATION_ID, id);
// Using commit on purpose because we might go out of sync if multiple notifications come
editor.commit();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment