19f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar/* 29f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * Copyright 2018 The Android Open Source Project 39f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * 49f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * Licensed under the Apache License, Version 2.0 (the "License"); 59f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * you may not use this file except in compliance with the License. 69f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * You may obtain a copy of the License at 79f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * 89f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * http://www.apache.org/licenses/LICENSE-2.0 99f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * 109f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * Unless required by applicable law or agreed to in writing, software 119f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * distributed under the License is distributed on an "AS IS" BASIS, 129f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * See the License for the specific language governing permissions and 149f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * limitations under the License. 159f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar */ 169f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 179f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarpackage androidx.work.impl; 189f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 197f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport static androidx.work.impl.utils.PackageManagerHelper.setComponentEnabled; 207f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 217f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport android.content.Context; 227f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport android.os.Build; 239f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarimport android.support.annotation.NonNull; 249f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarimport android.support.annotation.RestrictTo; 257f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport android.support.annotation.VisibleForTesting; 26697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumarimport android.util.Log; 279f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 28e326592ec414dfe4c002e2840d9fc4aef0ee8747Rahul Ravikumarimport androidx.work.Configuration; 297f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport androidx.work.impl.background.systemalarm.SystemAlarmScheduler; 307f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport androidx.work.impl.background.systemalarm.SystemAlarmService; 317f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport androidx.work.impl.background.systemjob.SystemJobScheduler; 327f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport androidx.work.impl.background.systemjob.SystemJobService; 339f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarimport androidx.work.impl.model.WorkSpec; 349f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarimport androidx.work.impl.model.WorkSpecDao; 359f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 367f44b37e7640e4b91656e024d1754fa7a062a833Sumir Katariaimport java.lang.reflect.InvocationTargetException; 379f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarimport java.util.List; 389f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 399f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar/** 407f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria * Helper methods for {@link Scheduler}s. 417f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria * 429f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * Helps schedule {@link androidx.work.impl.model.WorkSpec}s while enforcing 439f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * {@link Scheduler#MAX_SCHEDULER_LIMIT}s. 449f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * 459f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * @hide 469f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar */ 479f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 489f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumarpublic class Schedulers { 499f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 507f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria private static final String TAG = "Schedulers"; 517f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria private static final String FIREBASE_JOB_SCHEDULER_CLASSNAME = 527f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria "androidx.work.impl.background.firebase.FirebaseJobScheduler"; 537f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 547f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria @VisibleForTesting 557f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria static final String FIREBASE_JOB_SERVICE_CLASSNAME = 567f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria "androidx.work.impl.background.firebase.FirebaseJobService"; 577f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 589f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar /** 599f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * Schedules {@link WorkSpec}s while honoring the {@link Scheduler#MAX_SCHEDULER_LIMIT}. 609f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * 619f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * @param workDatabase The {@link WorkDatabase}. 629f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar * @param schedulers The {@link List} of {@link Scheduler}s to delegate to. 639f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar */ 649f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar public static void schedule( 65e326592ec414dfe4c002e2840d9fc4aef0ee8747Rahul Ravikumar @NonNull Configuration configuration, 669f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar @NonNull WorkDatabase workDatabase, 679f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar List<Scheduler> schedulers) { 689f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 699f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar WorkSpecDao workSpecDao = workDatabase.workSpecDao(); 70e326592ec414dfe4c002e2840d9fc4aef0ee8747Rahul Ravikumar List<WorkSpec> eligibleWorkSpecs = 71e326592ec414dfe4c002e2840d9fc4aef0ee8747Rahul Ravikumar workSpecDao.getEligibleWorkForScheduling( 72e326592ec414dfe4c002e2840d9fc4aef0ee8747Rahul Ravikumar configuration.getMaxSchedulerLimit()); 739f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar scheduleInternal(workDatabase, schedulers, eligibleWorkSpecs); 749f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 759f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 769f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar private static void scheduleInternal( 779f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar @NonNull WorkDatabase workDatabase, 789f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar List<Scheduler> schedulers, 799f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar List<WorkSpec> workSpecs) { 809f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 819f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar if (workSpecs == null || schedulers == null) { 829f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar return; 839f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 849f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar 859f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar long now = System.currentTimeMillis(); 869f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar WorkSpecDao workSpecDao = workDatabase.workSpecDao(); 879f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar // Mark all the WorkSpecs as scheduled. 889f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar // Calls to Scheduler#schedule() could potentially result in more schedules 899f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar // on a separate thread. Therefore, this needs to be done first. 909f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar workDatabase.beginTransaction(); 919f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar try { 929f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar for (WorkSpec workSpec : workSpecs) { 939f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar workSpecDao.markWorkSpecScheduled(workSpec.id, now); 949f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 959f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar workDatabase.setTransactionSuccessful(); 969f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } finally { 979f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar workDatabase.endTransaction(); 989f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 999f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar WorkSpec[] eligibleWorkSpecsArray = workSpecs.toArray(new WorkSpec[0]); 1009f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar // Delegate to the underlying scheduler. 1019f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar for (Scheduler scheduler : schedulers) { 1029f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar scheduler.schedule(eligibleWorkSpecsArray); 1039f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 1049f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar } 1057f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 10622a8129c2b3313100f851460f7da9e56ca98bd8fRahul Ravikumar static @NonNull Scheduler createBestAvailableBackgroundScheduler( 10722a8129c2b3313100f851460f7da9e56ca98bd8fRahul Ravikumar @NonNull Context context, 108494b77cd228de249649440c6210bbae1ddf33d76Rahul Ravikumar @NonNull WorkManagerImpl workManager) { 10922a8129c2b3313100f851460f7da9e56ca98bd8fRahul Ravikumar 1107f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria Scheduler scheduler; 1117f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria boolean enableFirebaseJobService = false; 1127f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria boolean enableSystemAlarmService = false; 1137f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 1147f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) { 115494b77cd228de249649440c6210bbae1ddf33d76Rahul Ravikumar scheduler = new SystemJobScheduler(context, workManager); 1167f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria setComponentEnabled(context, SystemJobService.class, true); 117697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, "Created SystemJobScheduler and enabled SystemJobService"); 1187f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } else { 1197f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria try { 1207f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria scheduler = tryCreateFirebaseJobScheduler(context); 1217f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria enableFirebaseJobService = true; 122697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, "Created FirebaseJobScheduler"); 1237f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } catch (Exception e) { 1247f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria // Also catches the exception thrown if Play Services was not found on the device. 1257f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria scheduler = new SystemAlarmScheduler(context); 1267f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria enableSystemAlarmService = true; 127697d6a4a3797bc71d0dd8685937a318e9934066bRahul Ravikumar Log.d(TAG, "Created SystemAlarmScheduler"); 1287f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } 1297f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } 1307f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 1316aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria try { 1326aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria Class firebaseJobServiceClass = Class.forName(FIREBASE_JOB_SERVICE_CLASSNAME); 1336aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria setComponentEnabled(context, firebaseJobServiceClass, enableFirebaseJobService); 1346aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria } catch (ClassNotFoundException e) { 1356aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria // Do nothing. 1366aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria } 1376aa349fecb357634a176b8ca3343231eefcee249Sumir Kataria 1387f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria setComponentEnabled(context, SystemAlarmService.class, enableSystemAlarmService); 1397f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 1407f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria return scheduler; 1417f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } 1427f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria 1437f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria @NonNull 1447f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria private static Scheduler tryCreateFirebaseJobScheduler(@NonNull Context context) 1457f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria throws ClassNotFoundException, IllegalAccessException, InstantiationException, 1467f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria InvocationTargetException, NoSuchMethodException { 1477f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria Class<?> firebaseJobSchedulerClass = Class.forName(FIREBASE_JOB_SCHEDULER_CLASSNAME); 1487f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria return (Scheduler) firebaseJobSchedulerClass 1497f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria .getConstructor(Context.class) 1507f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria .newInstance(context); 1517f44b37e7640e4b91656e024d1754fa7a062a833Sumir Kataria } 152f97ddbc502678a00306afcd73e7a6bb3bcc4c189Sumir Kataria 153f97ddbc502678a00306afcd73e7a6bb3bcc4c189Sumir Kataria private Schedulers() { 154f97ddbc502678a00306afcd73e7a6bb3bcc4c189Sumir Kataria } 1559f91ee8c71606f36a51177cd0b5c3005834be1ffRahul Ravikumar} 156