Skip to content

Commit f447f87

Browse files
authored
feat(notification): LP-5014 Add support 2 lines text at BigPictureStyle pus n… (#104)
* feat(notification): Add support 2 lines text at BigPictureStyle pus notification. * bump support library from 14.0.0 to 22.0.0
1 parent 10da4d1 commit f447f87

File tree

4 files changed

+189
-26
lines changed

4 files changed

+189
-26
lines changed

AndroidSDK/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ allprojects {
1717
dependencies {
1818
// Compile dependencies will be added as dependency in pom file.
1919
//noinspection GradleDynamicVersion
20-
compile "com.android.support:support-v4:[14.0.0,${SUPPORT_LIBRARY_VERSION}]"
20+
compile "com.android.support:support-v4:[22.0.0,${SUPPORT_LIBRARY_VERSION}]"
2121
//noinspection GradleDynamicVersion
22-
compile "com.android.support:appcompat-v7:[14.0.0,${SUPPORT_LIBRARY_VERSION}]"
22+
compile "com.android.support:appcompat-v7:[22.0.0,${SUPPORT_LIBRARY_VERSION}]"
2323

2424
// Provided dependencies are optional dependencies and will not show up in pom file.
2525
provided('com.google.android.gms:play-services-gcm:[8.3.0,)') {

AndroidSDK/src/com/leanplum/Leanplum.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ public void onResponse(boolean success) {
821821
public void run() {
822822
try {
823823
NotificationCompat.Builder builder =
824-
LeanplumNotificationHelper.getDefaultNotificationBuilder(context,
824+
LeanplumNotificationHelper.getDefaultCompatNotificationBuilder(context,
825825
BuildUtil.isNotificationChannelSupported(context));
826826
if (builder == null) {
827827
return;

AndroidSDK/src/com/leanplum/LeanplumNotificationHelper.java

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,19 @@
2020
*/
2121
package com.leanplum;
2222

23+
import android.app.Notification;
24+
import android.app.PendingIntent;
2325
import android.content.Context;
26+
import android.content.res.Resources;
27+
import android.graphics.Bitmap;
28+
import android.os.Build;
2429
import android.os.Bundle;
2530
import android.support.v4.app.NotificationCompat;
2631
import android.text.TextUtils;
32+
import android.util.TypedValue;
33+
import android.widget.RemoteViews;
2734

35+
import com.leanplum.internal.Constants;
2836
import com.leanplum.internal.JsonConverter;
2937
import com.leanplum.internal.Log;
3038
import com.leanplum.utils.BuildUtil;
@@ -37,6 +45,10 @@
3745
* @author Anna Orlova
3846
*/
3947
class LeanplumNotificationHelper {
48+
49+
private static final int BIGPICTURE_TEXT_TOP_PADDING = -14;
50+
private static final int BIGPICTURE_TEXT_SIZE = 14;
51+
4052
/**
4153
* If notification channels are supported this method will try to create
4254
* NotificationCompat.Builder with default notification channel if default channel id is provided.
@@ -49,7 +61,7 @@ class LeanplumNotificationHelper {
4961
*/
5062
// NotificationCompat.Builder(Context context) constructor was deprecated in API level 26.
5163
@SuppressWarnings("deprecation")
52-
static NotificationCompat.Builder getDefaultNotificationBuilder(Context context,
64+
static NotificationCompat.Builder getDefaultCompatNotificationBuilder(Context context,
5365
boolean isNotificationChannelSupported) {
5466
if (!isNotificationChannelSupported) {
5567
return new NotificationCompat.Builder(context);
@@ -63,6 +75,32 @@ static NotificationCompat.Builder getDefaultNotificationBuilder(Context context,
6375
}
6476
}
6577

78+
/**
79+
* If notification channels are supported this method will try to create
80+
* Notification.Builder with default notification channel if default channel id is provided.
81+
* If notification channels not supported this method will return Notification.Builder for
82+
* context.
83+
*
84+
* @param context The application context.
85+
* @param isNotificationChannelSupported True if notification channels are supported.
86+
* @return Notification.Builder for provided context or null.
87+
*/
88+
// Notification.Builder(Context context) constructor was deprecated in API level 26.
89+
@SuppressWarnings("deprecation")
90+
private static Notification.Builder getDefaultNotificationBuilder(Context context,
91+
boolean isNotificationChannelSupported) {
92+
if (!isNotificationChannelSupported) {
93+
return new Notification.Builder(context);
94+
}
95+
String channelId = LeanplumNotificationChannel.getDefaultNotificationChannelId(context);
96+
if (!TextUtils.isEmpty(channelId)) {
97+
return new Notification.Builder(context, channelId);
98+
} else {
99+
Log.w("Failed to post notification, there are no notification channels configured.");
100+
return null;
101+
}
102+
}
103+
66104
/**
67105
* If notification channels are supported this method will try to create a channel with
68106
* information from the message if it doesn't exist and return NotificationCompat.Builder for this
@@ -76,7 +114,7 @@ static NotificationCompat.Builder getDefaultNotificationBuilder(Context context,
76114
*/
77115
// NotificationCompat.Builder(Context context) constructor was deprecated in API level 26.
78116
@SuppressWarnings("deprecation")
79-
static NotificationCompat.Builder getNotificationBuilder(Context context, Bundle message) {
117+
static NotificationCompat.Builder getNotificationCompatBuilder(Context context, Bundle message) {
80118
NotificationCompat.Builder builder = null;
81119
// If we are targeting API 26, try to find supplied channel to post notification.
82120
if (BuildUtil.isNotificationChannelSupported(context)) {
@@ -94,7 +132,7 @@ static NotificationCompat.Builder getNotificationBuilder(Context context, Bundle
94132
}
95133
} else {
96134
// If channel isn't supplied, try to look up for default channel.
97-
builder = LeanplumNotificationHelper.getDefaultNotificationBuilder(context, true);
135+
builder = LeanplumNotificationHelper.getDefaultCompatNotificationBuilder(context, true);
98136
}
99137
} catch (Exception e) {
100138
Log.e("Failed to post notification to specified channel.");
@@ -104,4 +142,111 @@ static NotificationCompat.Builder getNotificationBuilder(Context context, Bundle
104142
}
105143
return builder;
106144
}
145+
146+
/**
147+
* If notification channels are supported this method will try to create a channel with
148+
* information from the message if it doesn't exist and return Notification.Builder for this
149+
* channel. In the case where no channel information inside the message, we will try to get a
150+
* channel with default channel id. If notification channels not supported this method will return
151+
* Notification.Builder for context.
152+
*
153+
* @param context The application context.
154+
* @param message Push notification Bundle.
155+
* @return Notification.Builder or null.
156+
*/
157+
static Notification.Builder getNotificationBuilder(Context context, Bundle message) {
158+
Notification.Builder builder = null;
159+
// If we are targeting API 26, try to find supplied channel to post notification.
160+
if (BuildUtil.isNotificationChannelSupported(context)) {
161+
try {
162+
String channel = message.getString("lp_channel");
163+
if (!TextUtils.isEmpty(channel)) {
164+
// Create channel if it doesn't exist and post notification to that channel.
165+
Map<String, Object> channelDetails = JsonConverter.fromJson(channel);
166+
String channelId = LeanplumNotificationChannel.createNotificationChannel(context,
167+
channelDetails);
168+
if (!TextUtils.isEmpty(channelId)) {
169+
builder = new Notification.Builder(context, channelId);
170+
} else {
171+
Log.w("Failed to post notification to specified channel.");
172+
}
173+
} else {
174+
// If channel isn't supplied, try to look up for default channel.
175+
builder = LeanplumNotificationHelper.getDefaultNotificationBuilder(context, true);
176+
}
177+
} catch (Exception e) {
178+
Log.e("Failed to post notification to specified channel.");
179+
}
180+
} else {
181+
builder = new Notification.Builder(context);
182+
}
183+
return builder;
184+
}
185+
186+
/**
187+
* Gets Notification.Builder with 2 lines at BigPictureStyle notification text.
188+
*
189+
* @param context The application context.
190+
* @param message Push notification Bundle.
191+
* @param contentIntent PendingIntent.
192+
* @param title String with title for push notification.
193+
* @param messageText String with text for push notification.
194+
* @param bigPicture Bitmap for BigPictureStyle notification.
195+
* @return Notification.Builder or null.
196+
*/
197+
static Notification.Builder getNotificationBuilder(Context context, Bundle message,
198+
PendingIntent contentIntent, String title, final String messageText, Bitmap bigPicture) {
199+
if (Build.VERSION.SDK_INT < 16) {
200+
return null;
201+
}
202+
Notification.Builder notificationBuilder =
203+
getNotificationBuilder(context, message);
204+
notificationBuilder.setSmallIcon(context.getApplicationInfo().icon)
205+
.setContentTitle(title)
206+
.setContentText(messageText);
207+
Notification.BigPictureStyle bigPictureStyle = new Notification.BigPictureStyle() {
208+
@Override
209+
protected RemoteViews getStandardView(int layoutId) {
210+
RemoteViews remoteViews = super.getStandardView(layoutId);
211+
// Modifications of stanxdard push RemoteView.
212+
try {
213+
int id = Resources.getSystem().getIdentifier("text", "id", "android");
214+
remoteViews.setBoolean(id, "setSingleLine", false);
215+
remoteViews.setInt(id, "setLines", 2);
216+
if (Build.VERSION.SDK_INT < 23) {
217+
// Make text smaller.
218+
remoteViews.setViewPadding(id, 0, BIGPICTURE_TEXT_TOP_PADDING, 0, 0);
219+
remoteViews.setTextViewTextSize(id, TypedValue.COMPLEX_UNIT_SP, BIGPICTURE_TEXT_SIZE);
220+
}
221+
} catch (Throwable throwable) {
222+
Log.e("Cannot modify push notification layout.");
223+
}
224+
return remoteViews;
225+
}
226+
};
227+
228+
bigPictureStyle.bigPicture(bigPicture)
229+
.setBigContentTitle(title)
230+
.setSummaryText(message.getString(Constants.Keys.PUSH_MESSAGE_TEXT));
231+
notificationBuilder.setStyle(bigPictureStyle);
232+
233+
if (Build.VERSION.SDK_INT >= 24) {
234+
// By default we cannot reach getStandardView method on API>=24. I we call
235+
// createBigContentView, Android will call getStandardView method and we can get
236+
// modified RemoteView.
237+
try {
238+
RemoteViews remoteView = notificationBuilder.createBigContentView();
239+
if (remoteView != null) {
240+
// We need to set received RemoteView as a custom big content view.
241+
notificationBuilder.setCustomBigContentView(remoteView);
242+
}
243+
} catch (Throwable t) {
244+
Log.e("Cannot modify push notification layout.", t);
245+
}
246+
}
247+
248+
notificationBuilder.setAutoCancel(true);
249+
notificationBuilder.setContentIntent(contentIntent);
250+
return notificationBuilder;
251+
}
107252
}

AndroidSDK/src/com/leanplum/LeanplumPushService.java

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.leanplum.internal.Util;
5151
import com.leanplum.internal.VarCache;
5252
import com.leanplum.utils.BitmapUtil;
53+
import com.leanplum.utils.BuildUtil;
5354
import com.leanplum.utils.SharedPreferencesUtil;
5455

5556
import org.json.JSONException;
@@ -104,6 +105,7 @@ public class LeanplumPushService {
104105
private static final String OPEN_URL = "Open URL";
105106
private static final String URL = "URL";
106107
private static final String OPEN_ACTION = "Open";
108+
private static final int MAX_ONE_LINE_TEXT_LENGTH = 37;
107109
private static Class<? extends Activity> callbackClass;
108110
private static LeanplumCloudMessagingProvider provider;
109111
private static boolean isFirebaseEnabled = false;
@@ -299,7 +301,7 @@ static void handleNotification(final Context context, final Bundle message) {
299301
/**
300302
* Put the message into a notification and post it.
301303
*/
302-
private static void showNotification(Context context, Bundle message) {
304+
private static void showNotification(Context context, final Bundle message) {
303305
if (context == null || message == null) {
304306
return;
305307
}
@@ -318,28 +320,35 @@ private static void showNotification(Context context, Bundle message) {
318320
if (message.getString("title") != null) {
319321
title = message.getString("title");
320322
}
321-
final NotificationCompat.Builder builder =
322-
LeanplumNotificationHelper.getNotificationBuilder(context, message);
323+
final NotificationCompat.Builder notificationCompatBuilder =
324+
LeanplumNotificationHelper.getNotificationCompatBuilder(context, message);
323325

324-
if (builder == null) {
326+
if (notificationCompatBuilder == null) {
325327
return;
326328
}
327-
328-
builder.setSmallIcon(context.getApplicationInfo().icon)
329+
final String messageText = message.getString(Keys.PUSH_MESSAGE_TEXT);
330+
notificationCompatBuilder.setSmallIcon(context.getApplicationInfo().icon)
329331
.setContentTitle(title)
330332
.setStyle(new NotificationCompat.BigTextStyle()
331-
.bigText(message.getString(Keys.PUSH_MESSAGE_TEXT)))
332-
.setContentText(message.getString(Keys.PUSH_MESSAGE_TEXT));
333+
.bigText(messageText))
334+
.setContentText(messageText);
333335

334336
String imageUrl = message.getString(Keys.PUSH_MESSAGE_IMAGE_URL);
337+
Notification.Builder notificationBuilder = null;
335338
// BigPictureStyle support requires API 16 and higher.
336339
if (!TextUtils.isEmpty(imageUrl) && Build.VERSION.SDK_INT >= 16) {
337340
Bitmap bigPicture = BitmapUtil.getScaledBitmap(context, imageUrl);
338341
if (bigPicture != null) {
339-
builder.setStyle(new NotificationCompat.BigPictureStyle()
340-
.bigPicture(bigPicture)
341-
.setBigContentTitle(title)
342-
.setSummaryText(message.getString(Keys.PUSH_MESSAGE_TEXT)));
342+
if ((messageText != null && messageText.length() < MAX_ONE_LINE_TEXT_LENGTH) ||
343+
customizer != null) {
344+
notificationCompatBuilder.setStyle(new NotificationCompat.BigPictureStyle()
345+
.bigPicture(bigPicture)
346+
.setBigContentTitle(title)
347+
.setSummaryText(messageText));
348+
} else {
349+
notificationBuilder = LeanplumNotificationHelper.getNotificationBuilder(context, message, contentIntent, title,
350+
messageText, bigPicture);
351+
}
343352
} else {
344353
Log.w(String.format("Image download failed for push notification with big picture. " +
345354
"No image will be included with the push notification. Image URL: %s.", imageUrl));
@@ -349,16 +358,16 @@ private static void showNotification(Context context, Bundle message) {
349358
// Try to put a notification on top of the notification area. This method was deprecated in API
350359
// level 26. For API level 26 and above we must use setImportance(int) for each notification
351360
// channel, not for each notification message.
352-
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 26) {
361+
if (Build.VERSION.SDK_INT >= 16 && !BuildUtil.isNotificationChannelSupported(context)) {
353362
//noinspection deprecation
354-
builder.setPriority(Notification.PRIORITY_MAX);
363+
notificationCompatBuilder.setPriority(Notification.PRIORITY_MAX);
355364
}
356-
builder.setAutoCancel(true);
357-
builder.setContentIntent(contentIntent);
365+
notificationCompatBuilder.setAutoCancel(true);
366+
notificationCompatBuilder.setContentIntent(contentIntent);
358367

359368
if (LeanplumPushService.customizer != null) {
360369
try {
361-
LeanplumPushService.customizer.customize(builder, message);
370+
LeanplumPushService.customizer.customize(notificationCompatBuilder, message);
362371
} catch (Throwable t) {
363372
Log.e("Unable to customize push notification: ", Log.getStackTraceString(t));
364373
return;
@@ -385,16 +394,25 @@ private static void showNotification(Context context, Bundle message) {
385394
try {
386395
// Check if we have a chained message, and if it exists in var cache.
387396
if (ActionContext.shouldForceContentUpdateForChainedMessage(
388-
JsonConverter.fromJson(message.getString(Keys.PUSH_MESSAGE_ACTION)))) {
397+
JsonConverter.fromJson(message.getString(Keys.PUSH_MESSAGE_ACTION)))) {
389398
final int currentNotificationId = notificationId;
399+
final Notification.Builder currentNotificationBuilder = notificationBuilder;
390400
Leanplum.forceContentUpdate(new VariablesChangedCallback() {
391401
@Override
392402
public void variablesChanged() {
393-
notificationManager.notify(currentNotificationId, builder.build());
403+
if (currentNotificationBuilder != null) {
404+
notificationManager.notify(currentNotificationId, currentNotificationBuilder.build());
405+
} else {
406+
notificationManager.notify(currentNotificationId, notificationCompatBuilder.build());
407+
}
394408
}
395409
});
396410
} else {
397-
notificationManager.notify(notificationId, builder.build());
411+
if (notificationBuilder != null) {
412+
notificationManager.notify(notificationId, notificationBuilder.build());
413+
} else {
414+
notificationManager.notify(notificationId, notificationCompatBuilder.build());
415+
}
398416
}
399417
} catch (NullPointerException e) {
400418
Log.e("Unable to show push notification.", e);

0 commit comments

Comments
 (0)