11package com .backendless .push ;
22
3+ import android .app .Notification ;
4+ import android .app .NotificationChannel ;
5+ import android .app .NotificationManager ;
6+ import android .app .PendingIntent ;
7+ import android .content .Context ;
38import android .content .Intent ;
9+ import android .media .AudioAttributes ;
10+ import android .media .AudioManager ;
11+ import android .os .Handler ;
12+ import android .os .Looper ;
13+ import android .support .v4 .app .NotificationCompat ;
14+ import android .support .v4 .app .NotificationManagerCompat ;
415import android .util .Log ;
16+ import com .backendless .Backendless ;
17+ import com .backendless .ContextHandler ;
18+ import com .backendless .async .callback .AsyncCallback ;
19+ import com .backendless .exceptions .BackendlessFault ;
20+ import com .backendless .messaging .AndroidPushTemplate ;
21+ import com .backendless .messaging .PublishOptions ;
522import com .google .firebase .messaging .FirebaseMessagingService ;
623import com .google .firebase .messaging .RemoteMessage ;
724
25+ import java .util .concurrent .atomic .AtomicInteger ;
26+
827
928public class BackendlessFCMService extends FirebaseMessagingService
1029{
30+ private static final String IMMEDIATE_MESSAGE = "ImmediateMessage" ;
1131 private static final String TAG = BackendlessFCMService .class .getSimpleName ();
32+ private static AtomicInteger notificationIdGenerator ;
33+
34+ /**
35+ * <p>This method is intended for overriding.
36+ * <p>The notification payload can be found within intent extras: intent.getStringExtra(PublishOptions.<CONSTANT_VALUE>).
37+ * @param appContext Application context of current android app.
38+ * @param msgIntent Contains all notification data.
39+ * @return Return 'true' if you want backendless library to continue processing, 'false' otherwise.
40+ */
41+ public boolean onMessage ( Context appContext , Intent msgIntent )
42+ {
43+ Log .i ( TAG , "Notification has been received by default 'BackendlessFCMService' class. You may override this method in a custom fcm service class which extends from 'com.backendless.push.BackendlessFCMService'. The notification payload can be found within intent extras: msgIntent.getStringExtra(PublishOptions.<CONSTANT_VALUE>)." );
44+ return true ;
45+ }
46+
47+ public BackendlessFCMService ()
48+ {
49+ if ( BackendlessFCMService .notificationIdGenerator == null )
50+ BackendlessFCMService .notificationIdGenerator = new AtomicInteger ( Backendless .getNotificationIdGeneratorInitValue () );
51+ }
52+
53+ @ Override
54+ public final void onDestroy ()
55+ {
56+ super .onDestroy ();
57+ Backendless .saveNotificationIdGeneratorState ( BackendlessFCMService .notificationIdGenerator .get () );
58+ }
1259
1360 @ Override
1461 public final void onNewToken ( String token )
1562 {
1663 super .onNewToken ( token );
17- Intent msgWork = new Intent ( BackendlessPushService .ACTION_FCM_REFRESH_TOKEN );
18- msgWork .putExtra ( BackendlessPushService .KEY_DEVICE_TOKEN , token );
19- BackendlessPushService .enqueueWork ( this .getApplicationContext (), msgWork );
64+ Context appContext = ContextHandler .getAppContext ();
65+ this .refreshTokenOnBackendless ( appContext , token );
2066 }
2167
2268 @ Override
2369 public final void onMessageReceived ( RemoteMessage remoteMessage )
2470 {
25- Intent msgWork = remoteMessage .toIntent ();
26- msgWork .setAction ( BackendlessPushService .ACTION_FCM_ONMESSAGE );
27- BackendlessPushService .enqueueWork ( this .getApplicationContext (), msgWork );
71+ Intent msgIntent = remoteMessage .toIntent ();
72+ Context appContext = ContextHandler .getAppContext ();
73+
74+ boolean showPushNotification = this .onMessage ( appContext , msgIntent );
75+
76+ if ( showPushNotification )
77+ this .handleMessage ( appContext , msgIntent );
2878 }
2979
3080 @ Override
@@ -33,4 +83,147 @@ public void onDeletedMessages()
3383 super .onDeletedMessages ();
3484 Log .w ( TAG , "there are too many messages (>100) pending for this app or your device hasn't connected to FCM in more than one month." );
3585 }
86+
87+ private void handleMessage ( final Context context , Intent intent )
88+ {
89+ int notificationId = BackendlessFCMService .notificationIdGenerator .getAndIncrement ();
90+
91+ try
92+ {
93+ String immediatePush = intent .getStringExtra ( PublishOptions .ANDROID_IMMEDIATE_PUSH );
94+ if ( immediatePush != null )
95+ {
96+ AndroidPushTemplate androidPushTemplate = (AndroidPushTemplate ) weborb .util .io .Serializer .fromBytes ( immediatePush .getBytes (), weborb .util .io .Serializer .JSON , false );
97+
98+ if ( androidPushTemplate .getContentAvailable () != null && androidPushTemplate .getContentAvailable () == 1 )
99+ return ;
100+
101+ if ( androidPushTemplate .getName () == null || androidPushTemplate .getName ().isEmpty () )
102+ androidPushTemplate .setName ( BackendlessFCMService .IMMEDIATE_MESSAGE );
103+
104+ if ( android .os .Build .VERSION .SDK_INT > 25 )
105+ {
106+ if ( PushTemplateHelper .getNotificationChannel ( context , androidPushTemplate .getName () ) == null )
107+ androidPushTemplate .setName ( BackendlessFCMService .IMMEDIATE_MESSAGE );
108+ }
109+
110+ Notification notification = PushTemplateHelper .convertFromTemplate ( context , androidPushTemplate , intent .getExtras ().deepCopy (), notificationId );
111+ PushTemplateHelper .showNotification ( context , notification , androidPushTemplate .getName (), notificationId );
112+ return ;
113+ }
114+
115+ final String templateName = intent .getStringExtra ( PublishOptions .TEMPLATE_NAME );
116+ if ( templateName != null )
117+ {
118+ AndroidPushTemplate androidPushTemplate = PushTemplateHelper .getPushNotificationTemplates ().get ( templateName );
119+ if ( androidPushTemplate != null )
120+ {
121+ if ( androidPushTemplate .getContentAvailable () != null && androidPushTemplate .getContentAvailable () == 1 )
122+ return ;
123+
124+ Notification notification = PushTemplateHelper .convertFromTemplate ( context , androidPushTemplate , intent .getExtras ().deepCopy (), notificationId );
125+ intent .getExtras ().deepCopy ();
126+ PushTemplateHelper .showNotification ( context , notification , androidPushTemplate .getName (), notificationId );
127+ }
128+ return ;
129+ }
130+
131+
132+ final String message = intent .getStringExtra ( PublishOptions .MESSAGE_TAG );
133+ final String contentTitle = intent .getStringExtra ( PublishOptions .ANDROID_CONTENT_TITLE_TAG );
134+ final String summarySubText = intent .getStringExtra ( PublishOptions .ANDROID_SUMMARY_SUBTEXT_TAG );
135+ String soundResource = intent .getStringExtra ( PublishOptions .ANDROID_CONTENT_SOUND_TAG );
136+ fallBackMode ( context , message , contentTitle , summarySubText , soundResource , notificationId );
137+ }
138+ catch ( Throwable throwable )
139+ {
140+ Log .e ( TAG , "Error processing push notification" , throwable );
141+ }
142+ }
143+
144+ private void fallBackMode ( Context context , String message , String contentTitle , String summarySubText , String soundResource , final int notificationId )
145+ {
146+ final String channelName = "Fallback" ;
147+ final NotificationCompat .Builder notificationBuilder ;
148+
149+ // android.os.Build.VERSION_CODES.O == 26
150+ if ( android .os .Build .VERSION .SDK_INT > 25 )
151+ {
152+ final String channelId = Backendless .getApplicationId () + ":" + channelName ;
153+ NotificationManager notificationManager = (NotificationManager ) context .getSystemService ( Context .NOTIFICATION_SERVICE );
154+ NotificationChannel notificationChannel = notificationManager .getNotificationChannel ( channelId );
155+
156+ if ( notificationChannel == null )
157+ {
158+ notificationChannel = new NotificationChannel ( channelId , channelName , NotificationManager .IMPORTANCE_DEFAULT );
159+
160+ AudioAttributes audioAttributes = new AudioAttributes .Builder ()
161+ .setUsage ( AudioAttributes .USAGE_NOTIFICATION_RINGTONE )
162+ .setContentType ( AudioAttributes .CONTENT_TYPE_SONIFICATION )
163+ .setFlags ( AudioAttributes .FLAG_AUDIBILITY_ENFORCED )
164+ .setLegacyStreamType ( AudioManager .STREAM_NOTIFICATION )
165+ .build ();
166+
167+ notificationChannel .setSound ( PushTemplateHelper .getSoundUri ( context , soundResource ), audioAttributes );
168+ notificationManager .createNotificationChannel ( notificationChannel );
169+ }
170+
171+ notificationBuilder = new NotificationCompat .Builder ( context , notificationChannel .getId () );
172+ }
173+ else
174+ notificationBuilder = new NotificationCompat .Builder ( context );
175+
176+ notificationBuilder .setSound ( PushTemplateHelper .getSoundUri ( context , soundResource ), AudioManager .STREAM_NOTIFICATION );
177+
178+ int appIcon = context .getApplicationInfo ().icon ;
179+ if ( appIcon == 0 )
180+ appIcon = android .R .drawable .sym_def_app_icon ;
181+
182+ Intent notificationIntent = context .getPackageManager ().getLaunchIntentForPackage ( context .getApplicationInfo ().packageName );
183+ PendingIntent contentIntent = PendingIntent .getActivity ( context , 0 , notificationIntent , 0 );
184+
185+ notificationBuilder .setContentIntent ( contentIntent )
186+ .setSmallIcon ( appIcon )
187+ .setContentTitle ( contentTitle )
188+ .setSubText ( summarySubText )
189+ .setContentText ( message )
190+ .setWhen ( System .currentTimeMillis () )
191+ .setAutoCancel ( true )
192+ .build ();
193+
194+ final NotificationManagerCompat notificationManager = NotificationManagerCompat .from ( context );
195+ Handler handler = new Handler ( Looper .getMainLooper () );
196+ handler .post ( new Runnable ()
197+ {
198+ @ Override
199+ public void run ()
200+ {
201+ notificationManager .notify ( channelName , notificationId , notificationBuilder .build () );
202+ }
203+ } );
204+ }
205+
206+ private void refreshTokenOnBackendless ( final Context context , String newDeviceToken )
207+ {
208+ Backendless .Messaging .refreshDeviceToken ( newDeviceToken , new AsyncCallback <Boolean >()
209+ {
210+ @ Override
211+ public void handleResponse ( Boolean response )
212+ {
213+ if ( response )
214+ Log .d ( TAG , "Device token refreshed successfully." );
215+ else
216+ {
217+ Log .d ( TAG , "Device is not registered on any channel." );
218+ FCMRegistration .unregisterDeviceOnFCM ( context , null );
219+ }
220+ }
221+
222+ @ Override
223+ public void handleFault ( BackendlessFault fault )
224+ {
225+ Log .e ( TAG , "Can not refresh device token on Backendless. " + fault .getMessage () );
226+ }
227+ } );
228+ }
36229}
0 commit comments