From ac96cae10f899c9d708a28fae74e3a4699a53904 Mon Sep 17 00:00:00 2001 From: Phil Lopreiato Date: Sat, 7 Mar 2020 19:52:50 -0500 Subject: [PATCH] Run Notification Processing via JobScheduler API (#946) * run notification processing via job scheduler * lint --- android/src/main/AndroidManifest.xml | 5 +- .../di/components/NotificationComponent.java | 3 +- .../gcm/GCMBroadcastReceiver.java | 14 ++---- .../androidclient/gcm/GCMMessageHandler.java | 36 ++++++------- .../androidclient/TestTbaAndroid.java | 2 - .../gcm/TestGCMBroadcastReceiver.java | 50 +++++++++++++++++++ scripts/test_notification.py | 2 +- 7 files changed, 79 insertions(+), 33 deletions(-) create mode 100644 android/src/test/java/com/thebluealliance/androidclient/gcm/TestGCMBroadcastReceiver.java diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 1f977fe24..0e69835ac 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -230,7 +230,10 @@ android:name=".receivers.NotificationChangedReceiver" android:exported="false" /> - + diff --git a/android/src/main/java/com/thebluealliance/androidclient/di/components/NotificationComponent.java b/android/src/main/java/com/thebluealliance/androidclient/di/components/NotificationComponent.java index 4ffbdcbb1..8f08f5918 100644 --- a/android/src/main/java/com/thebluealliance/androidclient/di/components/NotificationComponent.java +++ b/android/src/main/java/com/thebluealliance/androidclient/di/components/NotificationComponent.java @@ -3,6 +3,7 @@ import com.thebluealliance.androidclient.config.ConfigModule; import com.thebluealliance.androidclient.datafeed.gce.GceModule; import com.thebluealliance.androidclient.gcm.GCMMessageHandler; +import com.thebluealliance.androidclient.gcm.GcmModule; import com.thebluealliance.androidclient.renderers.RendererModule; import javax.inject.Singleton; @@ -11,7 +12,7 @@ @Singleton @Component( - modules = {GceModule.class, RendererModule.class, ConfigModule.class}, + modules = {GceModule.class, RendererModule.class, ConfigModule.class, GcmModule.class}, dependencies = ApplicationComponent.class) public interface NotificationComponent { void inject(GCMMessageHandler gcmMessageHandler); diff --git a/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMBroadcastReceiver.java b/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMBroadcastReceiver.java index b1a0c0424..0722e50f6 100644 --- a/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMBroadcastReceiver.java +++ b/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMBroadcastReceiver.java @@ -1,22 +1,16 @@ package com.thebluealliance.androidclient.gcm; -import android.app.Activity; -import android.content.ComponentName; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import androidx.legacy.content.WakefulBroadcastReceiver; import com.thebluealliance.androidclient.TbaLogger; -public class GCMBroadcastReceiver extends WakefulBroadcastReceiver { +public class GCMBroadcastReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { TbaLogger.d("Got GCM Message. " + intent); - // Explicitly specify that GcmIntentService will handle the intent. - ComponentName comp = new ComponentName(context.getPackageName(), - GCMMessageHandler.class.getName()); - // Start the service, keeping the device awake while it is launching. - startWakefulService(context, intent.setComponent(comp)); - setResultCode(Activity.RESULT_OK); + GCMMessageHandler.enqueueWork(context, intent); } } diff --git a/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMMessageHandler.java b/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMMessageHandler.java index 26d2c0e36..8219773dd 100644 --- a/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMMessageHandler.java +++ b/android/src/main/java/com/thebluealliance/androidclient/gcm/GCMMessageHandler.java @@ -1,6 +1,5 @@ package com.thebluealliance.androidclient.gcm; -import android.app.IntentService; import android.app.Notification; import android.content.Context; import android.content.Intent; @@ -8,6 +7,8 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; + +import androidx.core.app.JobIntentService; import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; @@ -55,7 +56,7 @@ import javax.inject.Inject; -public class GCMMessageHandler extends IntentService implements FollowsChecker { +public class GCMMessageHandler extends JobIntentService implements FollowsChecker { /** * Stack (bundle) notifications together into a Group for better UX on Nougat+ and Android Wear @@ -74,6 +75,9 @@ public class GCMMessageHandler extends IntentService implements FollowsChecker { /** If grouping won't work, use this ID to make each notification replace its predecessor. */ public static final int SINGULAR_NOTIFICATION_ID = 363; + public static final int JOB_ID = 254; + + @Inject GoogleCloudMessaging mCloudMessaging; @Inject MyTbaDatafeed mMyTbaDatafeed; @Inject DatabaseWriter mWriter; @Inject SharedPreferences mPrefs; @@ -86,14 +90,6 @@ public class GCMMessageHandler extends IntentService implements FollowsChecker { private NotificationComponent mComponenet; - public GCMMessageHandler() { - this("GCMMessageHandler"); - } - - public GCMMessageHandler(String name) { - super(name); - } - @Override public void onCreate() { super.onCreate(); @@ -109,6 +105,7 @@ private void getComponent() { .datafeedModule(application.getDatafeedModule()) .rendererModule(new RendererModule()) .authModule(application.getAuthModule()) + .gcmModule(application.getGcmModule()) .build(); } } @@ -131,14 +128,19 @@ public boolean followsTeam(Context context, String teamNumber, String matchKey, || subTable.hasNotificationType(teamAtEventInterestKey, notificationType); } - @Override - protected void onHandleIntent(Intent intent) { + public static void enqueueWork(Context context, Intent work) { + enqueueWork(context, GCMMessageHandler.class, JOB_ID, work); + } + @Override + protected void onHandleWork(Intent intent) { Bundle extras = intent.getExtras(); + if (extras == null) { + TbaLogger.w("Intent with no extras!"); + return; + } - GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); - - String messageType = gcm.getMessageType(intent); + String messageType = mCloudMessaging.getMessageType(intent); TbaLogger.d("GCM Message type: " + messageType); TbaLogger.d("Intent extras: " + extras.toString()); @@ -148,8 +150,6 @@ protected void onHandleIntent(Intent intent) { handleMessage(getApplicationContext(), type, data); TbaLogger.i("Received : (" + type + ") " + data); - - GCMBroadcastReceiver.completeWakefulIntent(intent); } public void handleMessage(Context c, String messageType, String messageData) { @@ -255,7 +255,7 @@ public void handleMessage(Context c, String messageType, String messageData) { } } catch (Exception e) { // We probably tried to post a null notification or something like that. Oops... - e.printStackTrace(); + TbaLogger.e("Error parsing notification", e); } } diff --git a/android/src/test/java/com/thebluealliance/androidclient/TestTbaAndroid.java b/android/src/test/java/com/thebluealliance/androidclient/TestTbaAndroid.java index 22ea0cf8e..e8dcc47d4 100644 --- a/android/src/test/java/com/thebluealliance/androidclient/TestTbaAndroid.java +++ b/android/src/test/java/com/thebluealliance/androidclient/TestTbaAndroid.java @@ -1,6 +1,5 @@ package com.thebluealliance.androidclient; -import com.google.firebase.FirebaseApp; import com.thebluealliance.androidclient.di.DaggerMockApplicationComponent; import com.thebluealliance.androidclient.di.DaggerMockDatafeedComponent; import com.thebluealliance.androidclient.di.MockAccountModule; @@ -29,7 +28,6 @@ public class TestTbaAndroid extends TbaAndroid { @Override public void onCreate() { disableStetho(); - FirebaseApp.initializeApp(this); super.onCreate(); } diff --git a/android/src/test/java/com/thebluealliance/androidclient/gcm/TestGCMBroadcastReceiver.java b/android/src/test/java/com/thebluealliance/androidclient/gcm/TestGCMBroadcastReceiver.java new file mode 100644 index 000000000..acc96fad1 --- /dev/null +++ b/android/src/test/java/com/thebluealliance/androidclient/gcm/TestGCMBroadcastReceiver.java @@ -0,0 +1,50 @@ +package com.thebluealliance.androidclient.gcm; + +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.Context; +import android.content.Intent; + +import com.google.gson.JsonObject; +import com.thebluealliance.androidclient.datafeed.framework.ModelMaker; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.annotation.Nullable; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import static org.junit.Assert.assertNotNull; + +@RunWith(AndroidJUnit4.class) +public class TestGCMBroadcastReceiver { + + private Context mApplicationContext; + private JobScheduler mJobScheduler; + + @Before + public void setUp() { + mApplicationContext = ApplicationProvider.getApplicationContext(); + mJobScheduler = (JobScheduler) mApplicationContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); + } + + @Test + public void testSchedulesJob() { + Intent intent = buildIntent(); + mApplicationContext.sendBroadcast(intent); + + @Nullable JobInfo job = mJobScheduler.getPendingJob(GCMMessageHandler.JOB_ID); + assertNotNull(job); + } + + private Intent buildIntent() { + JsonObject notificationData = ModelMaker.getModel(JsonObject.class, "notification_upcoming_match"); + Intent intent = new Intent("com.google.android.c2dm.intent.RECEIVE"); + intent.putExtra("notification_type", "upcoming_match"); + intent.putExtra("message_data", notificationData.toString()); + return intent; + } +} diff --git a/scripts/test_notification.py b/scripts/test_notification.py index 238aa67d8..cfe10de6f 100755 --- a/scripts/test_notification.py +++ b/scripts/test_notification.py @@ -46,7 +46,7 @@ def notify(message_type, json_data): --es message_data '%s'""" command = template % (message_type, json_text) - print "\nSending " + message_type + " broadcast" + print("\nSending " + message_type + " broadcast") subprocess.call(["adb", "shell", command])