package com.james.status.data; import android.annotation.TargetApi; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.service.notification.StatusBarNotification; import android.support.annotation.Nullable; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.app.NotificationCompat; import com.james.status.utils.PreferenceUtils; public class NotificationData implements Parcelable { public String category, title, subtitle, packageName, group, key, tag = ""; public int priority, id, iconRes, color = Color.BLACK; private boolean isAlert; private Bitmap largeIcon; private Icon unloadedIcon, unloadedLargeIcon; public PendingIntent intent; public ActionData[] actions; @TargetApi(18) public NotificationData(StatusBarNotification sbn, String key) { this.key = key; init(sbn.getNotification(), sbn.getId(), sbn.getPackageName()); } public NotificationData(Notification notification, String packageName) { init(notification, -1, packageName); } public NotificationData(Notification notification, int id, String packageName) { init(notification, id, packageName); } private void init(Notification notification, int id, String packageName) { category = NotificationCompat.getCategory(notification); title = getTitle(notification); subtitle = getSubtitle(notification); this.packageName = packageName; group = NotificationCompat.getGroup(notification); priority = notification.priority; this.id = id; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) this.color = notification.color; isAlert = notification.vibrate != null || notification.sound != null; Bundle extras = NotificationCompat.getExtras(notification); iconRes = extras.getInt(NotificationCompat.EXTRA_SMALL_ICON, 0); if (iconRes == 0 && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) iconRes = notification.icon; if (iconRes == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { unloadedIcon = extras.getParcelable(NotificationCompat.EXTRA_SMALL_ICON); if (unloadedIcon == null) unloadedIcon = notification.getSmallIcon(); } Object parcelable = extras.getParcelable(NotificationCompat.EXTRA_LARGE_ICON); if (parcelable != null) { if (parcelable instanceof Bitmap) largeIcon = (Bitmap) parcelable; else { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && parcelable instanceof Icon) { //throws a ClassNotFoundException? :P unloadedLargeIcon = (Icon) parcelable; } } catch (Exception ignored) { } } } if (largeIcon == null) { parcelable = extras.getParcelable(NotificationCompat.EXTRA_LARGE_ICON_BIG); if (parcelable instanceof Bitmap) largeIcon = (Bitmap) parcelable; else { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && parcelable instanceof Icon) { //throws a ClassNotFoundException? :P unloadedLargeIcon = (Icon) parcelable; } } catch (Exception ignored) { } } } if (largeIcon == null && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) largeIcon = notification.largeIcon; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) unloadedLargeIcon = notification.getLargeIcon(); intent = notification.contentIntent; actions = new ActionData[NotificationCompat.getActionCount(notification)]; for (int i = 0; i < actions.length; i++) { actions[i] = new ActionData(NotificationCompat.getAction(notification, i), packageName); } } protected NotificationData(Parcel in) { category = in.readString(); title = in.readString(); subtitle = in.readString(); packageName = in.readString(); group = in.readString(); key = in.readString(); tag = in.readString(); priority = in.readInt(); id = in.readInt(); color = in.readInt(); iconRes = in.readInt(); isAlert = in.readByte() == 1; if (in.readByte() == 1) largeIcon = Bitmap.CREATOR.createFromParcel(in); intent = PendingIntent.readPendingIntentOrNullFromParcel(in); int length = in.readInt(); actions = new ActionData[length]; for (int i = 0; i < length; i++) { actions[i] = in.readParcelable(ActionData.class.getClassLoader()); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { unloadedIcon = in.readParcelable(Icon.class.getClassLoader()); unloadedLargeIcon = in.readParcelable(Icon.class.getClassLoader()); } } public static final Creator<NotificationData> CREATOR = new Creator<NotificationData>() { @Override public NotificationData createFromParcel(Parcel in) { return new NotificationData(in); } @Override public NotificationData[] newArray(int size) { return new NotificationData[size]; } }; @Nullable public Drawable getIcon(Context context) { Drawable drawable = null; if (iconRes != 0) drawable = getDrawable(context, iconRes, packageName); if (drawable == null && unloadedIcon != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) drawable = unloadedIcon.loadDrawable(context); return drawable; } @Nullable public Drawable getLargeIcon(Context context) { Drawable drawable = null; if (largeIcon != null) drawable = new BitmapDrawable(context.getResources(), largeIcon); if (drawable == null && unloadedLargeIcon != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) drawable = unloadedLargeIcon.loadDrawable(context); return drawable; } public ActionData[] getActions() { return actions; } public String getName(Context context) { PackageManager packageManager = context.getPackageManager(); ApplicationInfo application; try { application = packageManager.getApplicationInfo(packageName, 0); } catch (final PackageManager.NameNotFoundException e) { return category; } return packageManager.getApplicationLabel(application).toString(); } public boolean shouldShowHeadsUp(Context context) { Boolean headsUp = PreferenceUtils.getBooleanPreference(context, PreferenceUtils.PreferenceIdentifier.STATUS_NOTIFICATIONS_HEADS_UP); return (headsUp != null ? headsUp : Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) && (priority >= NotificationCompat.PRIORITY_HIGH || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) && isAlert; } public boolean shouldHideStatusBar() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && priority >= NotificationCompat.PRIORITY_HIGH && isAlert; } public String getKey() { return String.valueOf(id) + "/" + packageName; } private String getTitle(Notification notification) { Bundle extras = NotificationCompat.getExtras(notification); String title = extras.getString(NotificationCompat.EXTRA_TITLE); return title != null ? title : ""; } private String getSubtitle(Notification notification) { Bundle extras = NotificationCompat.getExtras(notification); String subtitle = extras.getString(NotificationCompat.EXTRA_TEXT); if (subtitle == null) subtitle = extras.getString(NotificationCompat.EXTRA_SUB_TEXT); if (subtitle == null && notification.tickerText != null) subtitle = notification.tickerText.toString(); return subtitle != null ? subtitle : ""; } @Nullable private Drawable getDrawable(Context context, int resource, String packageName) { if (packageName == null) return null; Resources resources = null; PackageInfo packageInfo = null; try { resources = context.getPackageManager().getResourcesForApplication(packageName); packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException ignored) { } if (resources == null || packageInfo == null) return null; Resources.Theme theme = resources.newTheme(); theme.applyStyle(packageInfo.applicationInfo.theme, false); try { return ResourcesCompat.getDrawable(resources, resource, theme); } catch (Resources.NotFoundException | OutOfMemoryError e) { return null; } } public boolean equals(NotificationData obj) { return super.equals(obj) || (obj != null && obj.packageName.matches(packageName) && obj.id == id); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(category); dest.writeString(title); dest.writeString(subtitle); dest.writeString(packageName); dest.writeString(group); dest.writeString(key); dest.writeString(tag); dest.writeInt(priority); dest.writeInt(id); dest.writeInt(color); dest.writeInt(iconRes); dest.writeByte((byte) (isAlert ? 1 : 0)); if (largeIcon != null) { dest.writeByte((byte) 1); largeIcon.writeToParcel(dest, flags); } else dest.writeByte((byte) 0); PendingIntent.writePendingIntentOrNullToParcel(intent, dest); dest.writeInt(actions.length); for (ActionData action : actions) { dest.writeParcelable(action, flags); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { dest.writeParcelable(unloadedIcon, flags); dest.writeParcelable(unloadedLargeIcon, flags); } } }