From fc8235eccf8eb08727a130c6cfb1b0f1b27d4dbf Mon Sep 17 00:00:00 2001 From: Andrei Lazar Date: Fri, 6 Jul 2018 13:21:27 +0300 Subject: [PATCH] Bug 1473518 - Abide by Android Oreo background execution limits [Leanplum after upgrade] r=nalexander Refactored existing LeanplumPushInstanceIDService to support Oreo background execution limits in Leanplum after upgrade. MozReview-Commit-ID: JjUlrOv34KR *** --HG-- extra : amend_source : df46ff00a671a02dc1c6fda3d0402d9216d7e84f --- .../base/MmaAndroidManifest_services.xml.in | 11 +++ .../LeanplumGcmRegistrationJobService.java | 25 ++++++ .../leanplum/LeanplumNotificationHelper.java | 81 ++++++++++++++++++- .../LeanplumPushInstanceIDService.java | 16 ++-- 4 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 mobile/android/thirdparty/com/leanplum/LeanplumGcmRegistrationJobService.java diff --git a/mobile/android/base/MmaAndroidManifest_services.xml.in b/mobile/android/base/MmaAndroidManifest_services.xml.in index 5d2ca64e7c51..c4c9dc187ed9 100644 --- a/mobile/android/base/MmaAndroidManifest_services.xml.in +++ b/mobile/android/base/MmaAndroidManifest_services.xml.in @@ -9,6 +9,17 @@ + + + + + + + + + + diff --git a/mobile/android/thirdparty/com/leanplum/LeanplumGcmRegistrationJobService.java b/mobile/android/thirdparty/com/leanplum/LeanplumGcmRegistrationJobService.java new file mode 100644 index 000000000000..6e45a7c3a430 --- /dev/null +++ b/mobile/android/thirdparty/com/leanplum/LeanplumGcmRegistrationJobService.java @@ -0,0 +1,25 @@ +package com.leanplum; +import android.annotation.TargetApi; +import android.app.job.JobParameters; +import android.app.job.JobService; + +/** + * Leanplum GCM registration Job Service to start registration service. + * + * @author Anna Orlova + */ +@TargetApi(21) +public class LeanplumGcmRegistrationJobService extends JobService { + public static final int JOB_ID = -63722755; + + @Override + public boolean onStartJob(JobParameters jobParameters) { + LeanplumNotificationHelper.startPushRegistrationService(this, "GCM"); + return false; + } + + @Override + public boolean onStopJob(JobParameters jobParameters) { + return false; + } +} \ No newline at end of file diff --git a/mobile/android/thirdparty/com/leanplum/LeanplumNotificationHelper.java b/mobile/android/thirdparty/com/leanplum/LeanplumNotificationHelper.java index ee5235059bc2..2ac5ddda326f 100644 --- a/mobile/android/thirdparty/com/leanplum/LeanplumNotificationHelper.java +++ b/mobile/android/thirdparty/com/leanplum/LeanplumNotificationHelper.java @@ -24,14 +24,17 @@ package com.leanplum; import android.annotation.TargetApi; import android.app.Notification; import android.app.PendingIntent; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.TypedValue; @@ -42,7 +45,10 @@ import com.leanplum.internal.JsonConverter; import com.leanplum.internal.Log; import com.leanplum.utils.BuildUtil; +import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.TreeSet; /** * LeanplumNotificationHelper helper class for push notifications. @@ -81,6 +87,79 @@ class LeanplumNotificationHelper { } } + /** + * Starts push registration service to update GCM/FCM InstanceId token. + * + * @param context Current application context. + * @param providerName Name of push notification provider. + */ + static void startPushRegistrationService(Context context, String providerName) { + try { + if (context == null) { + return; + } + Log.i("Updating " + providerName + " InstanceId token."); + // Fetch updated Instance ID token and notify our app's server of any changes (if applicable). + Intent intent = new Intent(context, LeanplumPushRegistrationService.class); + context.startService(intent); + } catch (Throwable t) { + Log.e("Couldn't update " + providerName + " InstanceId token.", t); + } + } + + /** + * Schedule JobService to JobScheduler. + * + * @param context Current application context. + * @param clazz JobService class. + * @param jobId JobService id. + */ + @TargetApi(21) + static void scheduleJobService(Context context, Class clazz, int jobId) { + if (context == null) { + return; + } + ComponentName serviceName = new ComponentName(context, clazz); + JobScheduler jobScheduler = + (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + if (jobScheduler != null) { + jobId = verifyJobId(jobScheduler.getAllPendingJobs(), jobId); + JobInfo startMyServiceJobInfo = new JobInfo.Builder(jobId, serviceName) + .setMinimumLatency(10).build(); + jobScheduler.schedule(startMyServiceJobInfo); + } + } + + /** + * Verifies that jobId don't present on JobScheduler pending jobs. If jobId present on + * JobScheduler pending jobs generates a new one. + * + * @param allPendingJobs List of current pending jobs. + * @param jobId JobService id. + * @return jobId if jobId don't present on JobScheduler pending jobs + */ + @TargetApi(21) + private static int verifyJobId(List allPendingJobs, int jobId) { + if (allPendingJobs != null && !allPendingJobs.isEmpty()) { + TreeSet idsSet = new TreeSet<>(); + for (JobInfo jobInfo : allPendingJobs) { + idsSet.add(jobInfo.getId()); + } + if (idsSet.contains(jobId)) { + if (idsSet.first() > Integer.MIN_VALUE) { + jobId = idsSet.first() - 1; + } else if (idsSet.last() < Integer.MIN_VALUE) { + jobId = idsSet.last() + 1; + } else { + while (idsSet.contains(jobId)) { + jobId = new Random().nextInt(); + } + } + } + } + return jobId; + } + /** * If notification channels are supported this method will try to create * Notification.Builder with default notification channel if default channel id is provided. diff --git a/mobile/android/thirdparty/com/leanplum/LeanplumPushInstanceIDService.java b/mobile/android/thirdparty/com/leanplum/LeanplumPushInstanceIDService.java index e6f09e2b0d02..72d10e3a7822 100644 --- a/mobile/android/thirdparty/com/leanplum/LeanplumPushInstanceIDService.java +++ b/mobile/android/thirdparty/com/leanplum/LeanplumPushInstanceIDService.java @@ -21,7 +21,7 @@ package com.leanplum; -import android.content.Intent; +import android.os.Build; import com.google.android.gms.iid.InstanceIDListenerService; import com.leanplum.internal.Log; @@ -39,9 +39,15 @@ public class LeanplumPushInstanceIDService extends InstanceIDListenerService { */ @Override public void onTokenRefresh() { - Log.i("GCM InstanceID token needs an update"); - // Fetch updated Instance ID token and notify our app's server of any changes (if applicable). - Intent intent = new Intent(this, LeanplumPushRegistrationService.class); - startService(intent); + try { + if (Build.VERSION.SDK_INT < 26) { + LeanplumNotificationHelper.startPushRegistrationService(this, "GCM"); + } else { + LeanplumNotificationHelper.scheduleJobService(this, + LeanplumGcmRegistrationJobService.class, LeanplumGcmRegistrationJobService.JOB_ID); + } + } catch (Throwable t) { + Log.e("Failed to update GCM token.", t); + } } }