You are on page 1of 133

The evolution of notifications

@JeremMartinez
TrustBK
The new traditional bank
TrustBK

A Designed for SME

B Banker done right

C From scratch with no legacy

D Defend 3 core values: Trust, Technology, Ethics


We recruit!
www.trustbk.com/jobs
What is a
1 notification?
Definition

“A notification is a message you can display to the user outside


of your application's normal UI. […]

Both the notification area and the notification drawer are


system-controlled areas that the user can view at any time.”
Definition

“A notification is a message you can display to the user outside


of your application's normal UI. […]

Both the notification area and the notification drawer are


system-controlled areas that the user can view at any time.”
Awareness
I exist!
Quick access
and actions!
2 History
Gingerbread (2.3)

Content title

Content text 13:37


Ice Scream Sandwich (4.0)

Content title 13:37


Content text
SubText
Jelly Bean (4.1|2|3)

Content title 13:37


Content text
SubText

Action
Kitkat (4.4)

Content title 13:37


Content text
SubText

Action
Lollipop (5.0)

Content title 13:37


Content text
SubText

ACTION
Marshmallow (6.0)

Content title 13:37


Content text
SubText

ACTION
Nougat (7.0)

Droidcon SubText 13:37

Content title
Content text

ACTION
Android reo
Droidcon SubText 13:37

Content title
Content text

ACTION
Be a good
3 citizen
Letters SMS

Telegrams Emails

Phone calls Batman


]
Letters SMS

A M
P
Telegrams Emails

[ S
Phone calls Batman
1
Disruptions
through the day
Deletion
of information by mistake
Info forgotten
Bad timing
Amount

Priority
1 Category

Metadata
Amount

Priority
1 Category

Metadata
Amount

Priority
1 Category

Metadata

Importance
Channels
Global app view Channel view
4 Categorize
PAIN FUN
URGENT

PAIN FUN

NON-URGENT
URGENT

PAIN FUN

NON-URGENT
URGENT

FUN
VIP of our life
Urgent & Fun
URGENT

PAIN FUN

NON-URGENT
FUN

NON-URGENT
Procrastination
Non-urgent & Fun
URGENT

PAIN FUN

NON-URGENT
URGENT

PAIN
Livelihood
Urgent & Painful
URGENT

PAIN FUN

NON-URGENT
PAIN

NON-URGENT
Nagging
Non-urgent & Painful
2 main principles
to evaluate a notification
Be relevant
Help yourself with context
Be legitimate
Don’t lie about urgency
Use case
Scheduled
Always up to date
Scheduled
Urgent
5 Triggering
Notification notification = new NotificationCompat.Builder(this).
setSmallIcon(R.drawable.ic_notification).
setContentTitle("Title").
setContentText("Text").
build();

NotificationManagerCompat.from(this).notify(12345, notification);
Notification notification = new NotificationCompat.Builder(this).
setSmallIcon(R.drawable.ic_notification).
setContentTitle("Title").
setContentText("Text").
build();

NotificationManagerCompat.from(this).notify(12345, notification);
1. Local events
e.g. downloads, updates, posting a tweet
2. Scheduled
AlarmManager
context.getSystemService( AlarmManager.class);
alarmManager.setExact(type, triggerAtMillis, operation);
alarmManager.setExact(type, triggerAtMillis, operation);
setExact

if (BuildUtils.hasMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(type, millis, operation);
} else if (BuildUtils.hasKitKat()) {
alarmManager.setExact(type, millis, operation);
} else {
alarmManager.set(type, millis, operation);
}
setExact

if (BuildUtils.hasMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(type, millis, operation);
} else if (BuildUtils.hasKitKat()) {
alarmManager.setExact(type, millis, operation);
} else {
alarmManager.set(type, millis, operation);
}
setExact

if (BuildUtils.hasMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(type, millis, operation);
} else if (BuildUtils.hasKitKat()) {
alarmManager.setExact(type, millis, operation);
} else {
alarmManager.set(type, millis, operation);
}
setExact

if (BuildUtils.hasMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(type, millis, operation);
} else if (BuildUtils.hasKitKat()) {
alarmManager.setExact(type, millis, operation);
} else {
alarmManager.set(type, millis, operation);
}
alarmManager.setExact(type, triggerAtMillis, operation);
alarmManager.setExact (type, triggerAtMillis, operation);
type

System.currentTimeMillis()
time since boot including sleep

AlarmManager.RTC | AlarmManager.RTC_WAKEUP
type

SystemClock.elapsedRealtime()
wall clock time in UTC

AlarmManager.ELAPSED_REALTIME | AlarmManager.ELAPSED_REALTIME_WAKEUP
alarmManager.setExact (type, triggerAtMillis, operation);
alarmManager.setExact (type, triggerAtMillis, operation);
alarmManager.setExact (type, triggerAtMillis, operation);
operation PendingIntent

public static PendingIntent getActivity( … )

public static PendingIntent getService( … )

public static PendingIntent getBroadcast( … )


Is it that simple ?
final Intent intent = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent, intent,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);

=?
final Intent intent = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent, intent,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);
final Intent intent = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
1234, 1235,
intent, intent,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);

=?
final Intent intent = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
1234, 1235,
intent, intent,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);
final Intent intent1 = new Intent(this, MainActivity.class);
final Intent intent2 = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);

=?
final Intent intent1 = new Intent(this, MainActivity.class);
final Intent intent2 = new Intent(this, MainActivity.class);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);
final Intent intent1 = new Intent(this, MainActivity.class).
putExtra("extra1", "extra1");
final Intent intent2 = new Intent(this, MainActivity.class).
putExtra(“extra2", "extra2");

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);

=?
final Intent intent1 = new Intent(this, MainActivity.class).
putExtra("extra1", "extra1");
final Intent intent2 = new Intent(this, MainActivity.class).
putExtra(“extra2", "extra2");

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);
final Intent intent1 = new Intent(this, MainActivity.class).
addCategory(Intent.CATEGORY_APP_BROWSER);
final Intent intent2 = new Intent(this, MainActivity.class).
addCategory(Intent.CATEGORY_APP_CALCULATOR);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);

=?
final Intent intent1 = new Intent(this, MainActivity.class).
addCategory(Intent.CATEGORY_APP_BROWSER);
final Intent intent2 = new Intent(this, MainActivity.class).
addCategory(Intent.CATEGORY_APP_CALCULATOR);

PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
123, 123,
intent1, intent2,
FLAG_UPDATE_CURRENT); FLAG_UPDATE_CURRENT);
public boolean filterEquals(Intent other) {
if (other == null) {
return false;
}
if (!Objects.equals(this.mAction, other.mAction)) return false;
if (!Objects.equals(this.mData, other.mData)) return false;
if (!Objects.equals(this.mType, other.mType)) return false;
if (!Objects.equals(this.mPackage, other.mPackage)) return false;
if (!Objects.equals(this.mComponent, other.mComponent)) return false;
if (!Objects.equals(this.mCategories, other.mCategories)) return false;

return true;
}
It can be trickier…
Survive app upgrade
e N
a s
e l e
R
Register
PendingIntent

e N
a s
e l e
R
new Intent(this, MainActivity.class).
putExtra("extra1", "extra1");

Register
PendingIntent

e N
a s
e l e
R
Register
PendingIntent
“extra1" “extra2”

e N
a s Refactoring
e l e
R
Register
PendingIntent

N +1
se e N
l ea a s
e e l e
R R
Register
PendingIntent

N +1
se e N
l ea a s
e e l e
R R
new Intent(this, MainActivity.class).
putExtra("extra1", "extra1");

Register
PendingIntent

N +1
se e N
l ea a s
e e l e
R R
Register
PendingIntent

N +1 E
e N NP
a s se
e l e l ea
R Re
3. Realtime
Push notifications: GCM & Firebase
- Use extensively group

- Be careful about marketing abuse

- Don’t forget to remove notifications


Snooze
Time-out
6 Styling
Notification.Style

BigPictureStyle BigTextStyle MediaStyle

InboxStyle MessagingStyle
Default
BigText
BigPicture
Media
Notification.Style

DecoratedCustomViewStyle
RemoteViews
Run in another process
Avoid RemoteViews
Prefer default styling or span
Spanned everything!
Very powerful API — Available everywhere
SpannableString delayedSpanned = new SpannableString(delayed);

delayedSpanned.setSpan(new StrikethroughSpan(), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
delayedSpanned.setSpan(new ForegroundColorSpan(textColor), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
SpannableString delayedSpanned = new SpannableString(delayed);

delayedSpanned.setSpan(new StrikethroughSpan(), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
delayedSpanned.setSpan(new ForegroundColorSpan(textColor), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
SpannableString delayedSpanned = new SpannableString(delayed);

delayedSpanned.setSpan(new StrikethroughSpan(), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
delayedSpanned.setSpan(new ForegroundColorSpan(textColor), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
SpannableString delayedSpanned = new SpannableString(delayed);

delayedSpanned.setSpan(new StrikethroughSpan(), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
delayedSpanned.setSpan(new ForegroundColorSpan(textColor), //
0, delayedSpanned.length(), //
Spanned.SPAN_INCLUSIVE_INCLUSIVE);

textView.setText(delayedSpanned);
7 Other tips
Transient
Be able to find the same info
elsewhere in the app
Be patient
Wait for the content
Clean up
Delete outdated notification
Think VIP
Help Android to order
Think multi-devices
Synchronize notifications
8 Conclusion

www.trustbk.com @JeremMartinez

You might also like