I was looking for a way to enable multi line notifications for Firemonkey in Delphi 10 Seattle on Android and this is the solution I came up with. If you search for Android multiline notifications there are lots of solutions out there which are all in Java. The trick is to convert the Java into Object Pascal using the Delphi Android JNI. Two examples of how to add multiline notifications to Android in Java are here and here. I referenced these examples to create the solution. First I will describe how I came up with the solution so that you can follow this method when using the Android JNI to add other functionality and then I will list the full step by step guide at the end so you can skip the long explanation if you want. This code affects local notifications only as push notifications are defined elsewhere. You should be able to use this code with Appmethod and it can be adapted to C++Builder as well. Obviously it does not apply to IOS, OSX, or Windows.

Hacking The Android JNI

The solution involves creating a BigTextStyle and calling .setStyle() to apply it to the NotificationBuilder object. The code where NotificationBuilder is located is in System.Android.Notification.pas (or FMX.Notification.Android.pas under earlier versions of Delphi). You will need to copy this RTL unit to your project folder. I found the location by searching the RTL itself for ‘notificationManager’ with a Find In Files search using Textpad (my text editor of choice). Any fragment of the Java (or Object Pascal) code you are looking for can be used to search for the Android JNI interface equivalent in the RTL. The BigTextStyle interface object itself is not in the RTL so it will need to be added. It should be added into Androidapi.JNI.Support.pas so you will need to also copy this file into your project folder as well. I found the JNotificationCompat_Style definition by searching the RTL for ‘setStyle(‘. You can find the interface definition for BigTextStyle here on Github. All of the Object Pascal interface files for Android version 7 through 23 are also available from that Github repository as well. They were created with Java2Pas.

Creating The NotificationCompat.BigTextStyle Interface

In the interface definition there are three things I figured out through trial and error which I had to change. First the Java class which is defined as android/app/Notification_BigTextStyle actually needs to be defined as android/support/v4/app/NotificationCompat$BigTextStyle. I figured this out by looking at how the parent class was defined which is android/support/v4/app/NotificationCompat$Style. You can see the BigTextStyle class hierarchy here in the Android docs. Second, through trial and error I also figured out that I needed to change the JObject and JObjectClass interface definitions so that they became JNotificationCompat_Style and JNotificationCompat_StyleClass. This was required because .setStyle() needs a JNotificationCompat_Style parameter and it would not originally accept JNotification_BigTextStyle. And third I had to define the new JNotificationCompat_BigTextStyleClass interfaces below the JNotificationCompat_Style interface. I found it easier to merge the contents of android.app.Notification_BigTextStyle.pas into Androidapi.JNI.Support.pas. I just added the different sections of the JNotificationCompat_BigTextStyle interface after each comparable section of the JNotificationCompat_Style interface (which remember is the parent type).

Lastly I noticed that there was a section in Androidapi.JNI.Support.pas which looks like this TRegTypes.RegisterType(‘Androidapi.JNI.Support.JNotificationCompat_Style’, TypeInfo(Androidapi.JNI.Support.JNotificationCompat_Style)); so I added a similar line like this for the new BigTextStyle type TRegTypes.RegisterType(‘Androidapi.JNI.Support.JNotificationCompat_BigTextStyle’, TypeInfo(Androidapi.JNI.Support.JNotificationCompat_BigTextStyle));.

Adding setStyle() To System.Android.Notification

Once you have the BigTextStyle class defined the rest of the code is pretty straightforward. In System.Android.Notification.pas there is the CreateNativeNotification() function which is where JNotificationCompat_Builder is used. Referencing back to the original solution you will see how the Java code and the Object Pascal code are similar. For example, you will see calls to setContentTitle in both sets of code. I chose the setSmallIcon line to add the new code after but I’m not sure that it matters where you add in the new setStyle call. I looked at this line NotificationBuilder := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context); for guidance on how to create a new BigTextStyle object. A NotificationBuilder: JNotificationCompat_Builder; was defined in the var section so I added an equivalent BigTextStyle: JNotificationCompat_BigTextStyle; to the var section. I attempted BigTextStyle := TJNotificationCompat_BigTextStyle.JavaClass.init(NotificationBuilder); but that just ended up crashing the app. Through trial and error I ended up with BigTextStyle := TJNotificationCompat_BigTextStyle.JavaClass.init();

Referencing the Java and the Object Pascal code I could see that the message needed to be passed in to the bigText function and the message in Object Pascal was retrievable via GetContentText so I ended up with BigTextStyle.bigText(GetContentText); Finally I needed to apply the new BigTextStyle object to the NotificationBuilder which I did with NotificationBuilder := NotificationBuilder.setStyle(BigTextStyle); I mentioned about how setStyle would not originally take BigTextStyle because it was of the wrong type. So I actually ran into the wrong type issue at this point and this is when I went back into the BigTextStyle interface in Androidapi.JNI.Support.pas and upgraded it to subclass off of the original Style object.

Android MultiLine Notification Step By Step Guide

Step #1: Follow the instructions in the Delphi DocWiki to create a notification project. Here is that code snippet:

procedure TForm1.RepeatedNotificationClick(Sender: TObject); var MyNotification: TNotification; begin MyNotification := NotificationCenter1.CreateNotification; try MyNotification.Title := 'MyNotification'; MyNotification.AlertBody := 'Repeating notification each minute! But reaaaaallly reeeaaalllly long with lots of data here to make sure it shows up multiline.'; //Fired in 10 seconds MyNotification.FireDate := Now + EncodeTime(0, 0, 10, 0); //Repeated each minute MyNotification.RepeatInterval := TRepeatInterval.Minute; // Send notification to the notification center NotificationCenter1.ScheduleNotification(MyNotification); finally MyNotification.Free; end; end; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 procedure TForm1 . RepeatedNotificationClick ( Sender : TObject ) ; var MyNotification : TNotification ; begin MyNotification : = NotificationCenter1 . CreateNotification ; try MyNotification . Title : = 'MyNotification' ; MyNotification . AlertBody : = 'Repeating notification each minute! But reaaaaallly reeeaaalllly long with lots of data here to make sure it shows up multiline.' ; //Fired in 10 seconds MyNotification . FireDate : = Now + EncodeTime ( 0 , 0 , 10 , 0 ) ; //Repeated each minute MyNotification . RepeatInterval : = TRepeatInterval . Minute ; // Send notification to the notification center NotificationCenter1 . ScheduleNotification ( MyNotification ) ; finally MyNotification . Free ; end ; end ;

Step #2: Copy Androidapi.JNI.Support.pas and System.Android.Notification.pas (or FMX.Notification.Android.pas) to your project directory.

Step #3: Edit Androidapi.JNI.Support.pas.

Step #4: After this line:

JNotificationCompat_Style = interface;//android.support.v4.app.NotificationCompat$Style 1 JNotificationCompat_Style = interface ; //android.support.v4.app.NotificationCompat$Style

Add:

JNotificationCompat_BigTextStyle = interface; 1 JNotificationCompat_BigTextStyle = interface ;

Step #5:

After this line:

TJNotificationCompat_Style = class(TJavaGenericImport<JNotificationCompat_StyleClass, JNotificationCompat_Style>) end; 1 TJNotificationCompat_Style = class ( TJavaGenericImport & lt ; JNotificationCompat_StyleClass , JNotificationCompat_Style & gt ; ) end ;

Add:

JNotificationCompat_BigTextStyleClass = interface(JNotificationCompat_StyleClass) ['{0E443407-40E9-4985-9F1D-6D0CF1C5F652}'] function bigText(cs : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function init : JNotificationCompat_BigTextStyle; cdecl; overload; // ()V A: $1 function init(builder : JNotificationCompat_Builder) : JNotificationCompat_BigTextStyle; cdecl; overload;// (Landroid/app/Notification$Builder;)V A: $1 function setBigContentTitle(title : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl;// (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setSummaryText(cs : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl;// (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 end; // [JavaSignature('android/support/v4/app/NotificationCompat$BigTextStyle')] JNotificationCompat_BigTextStyle = interface(JNotificationCompat_Style) ['{3AFC570E-365A-4261-9954-ADE1BEC12986}'] function bigText(cs : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setBigContentTitle(title : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl;// (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setSummaryText(cs : JCharSequence) : JNotificationCompat_BigTextStyle; cdecl;// (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 end; // TJNotificationCompat_BigTextStyle = class(TJavaGenericImport<JNotificationCompat_BigTextStyleClass, JNotificationCompat_BigTextStyle>) end; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 JNotificationCompat_BigTextStyleClass = interface ( JNotificationCompat_StyleClass ) [ '{0E443407-40E9-4985-9F1D-6D0CF1C5F652}' ] function bigText ( cs : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function init : JNotificationCompat_BigTextStyle ; cdecl ; overload ; // ()V A: $1 function init ( builder : JNotificationCompat_Builder ) : JNotificationCompat_BigTextStyle ; cdecl ; overload ; // (Landroid/app/Notification$Builder;)V A: $1 function setBigContentTitle ( title : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setSummaryText ( cs : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 end ; // [ JavaSignature ( 'android/support/v4/app/NotificationCompat$BigTextStyle' ) ] JNotificationCompat_BigTextStyle = interface ( JNotificationCompat_Style ) [ '{3AFC570E-365A-4261-9954-ADE1BEC12986}' ] function bigText ( cs : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setBigContentTitle ( title : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 function setSummaryText ( cs : JCharSequence ) : JNotificationCompat_BigTextStyle ; cdecl ; // (Ljava/lang/CharSequence;)Landroid/app/Notification$BigTextStyle; A: $1 end ; // TJNotificationCompat_BigTextStyle = class ( TJavaGenericImport & lt ; JNotificationCompat_BigTextStyleClass , JNotificationCompat_BigTextStyle & gt ; ) end ;

Step #6:

After:

TRegTypes.RegisterType('Androidapi.JNI.Support.JNotificationCompat_Style', TypeInfo(Androidapi.JNI.Support.JNotificationCompat_Style)); 1 TRegTypes . RegisterType ( 'Androidapi.JNI.Support.JNotificationCompat_Style' , TypeInfo ( Androidapi . JNI . Support . JNotificationCompat_Style ) ) ;

Add:

TRegTypes.RegisterType('Androidapi.JNI.Support.JNotificationCompat_BigTextStyle', TypeInfo(Androidapi.JNI.Support.JNotificationCompat_BigTextStyle)); 1 TRegTypes . RegisterType ( 'Androidapi.JNI.Support.JNotificationCompat_BigTextStyle' , TypeInfo ( Androidapi . JNI . Support . JNotificationCompat_BigTextStyle ) ) ;

Step #7: Edit System.Android.Notification.pas (or FMX.Notification.Android.pas).

Step #8:

In this function:

function TNotificationCenterAndroid.CreateNativeNotification(const ANotification: TNotification): JNotification; 1 function TNotificationCenterAndroid . CreateNativeNotification ( const ANotification : TNotification ) : JNotification ;

Add:

var BigTextStyle: JNotificationCompat_BigTextStyle; 1 2 var BigTextStyle : JNotificationCompat_BigTextStyle ;

Step #9:

After:

NotificationBuilder := NotificationBuilder.setSmallIcon(GetDefaultIconID); 1 NotificationBuilder : = NotificationBuilder . setSmallIcon ( GetDefaultIconID ) ;

Add:

BigTextStyle := TJNotificationCompat_BigTextStyle.JavaClass.init(); BigTextStyle.bigText(GetContentText); NotificationBuilder := NotificationBuilder.setStyle(BigTextStyle); 1 2 3 BigTextStyle : = TJNotificationCompat_BigTextStyle . JavaClass . init ( ) ; BigTextStyle . bigText ( GetContentText ) ; NotificationBuilder : = NotificationBuilder . setStyle ( BigTextStyle ) ;

Step #10: Deploy your project to Android and test!

Lastly, there are actually four different styles that subclass off of NotificationCompat.Style. They are NotificationCompat.BigPictureStyle, NotificationCompat.BigTextStyle, NotificationCompat.InboxStyle, and NotificationCompat.MediaStyle. You can implement the other three custom styles yourself and use the full range of custom notifications with photos and more.

Check out the full Android documentation for NotificationCompat.Style and it’s sub classes.