Home | History | Annotate | Download | only in firebase
      1 /*
      2  * Copyright 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.work.impl.background.firebase;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.os.Build;
     24 import android.support.annotation.NonNull;
     25 import android.support.annotation.RestrictTo;
     26 import android.util.Log;
     27 
     28 import androidx.work.impl.Scheduler;
     29 import androidx.work.impl.model.WorkSpec;
     30 import androidx.work.impl.utils.IdGenerator;
     31 
     32 import com.firebase.jobdispatcher.FirebaseJobDispatcher;
     33 import com.firebase.jobdispatcher.GooglePlayDriver;
     34 import com.firebase.jobdispatcher.Job;
     35 import com.google.android.gms.common.ConnectionResult;
     36 import com.google.android.gms.common.GoogleApiAvailability;
     37 
     38 /**
     39  * A class that schedules work using {@link FirebaseJobDispatcher}.
     40  *
     41  * @hide
     42  */
     43 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     44 public class FirebaseJobScheduler implements Scheduler {
     45 
     46     private static final String TAG = "FirebaseJobScheduler";
     47 
     48     private final Context mAppContext;
     49     private final FirebaseJobDispatcher mDispatcher;
     50     private final FirebaseJobConverter mJobConverter;
     51 
     52     private IdGenerator mIdGenerator;
     53     private AlarmManager mAlarmManager;
     54 
     55     public FirebaseJobScheduler(@NonNull Context context) {
     56         mAppContext = context.getApplicationContext();
     57         boolean isPlayServicesAvailable = GoogleApiAvailability.getInstance()
     58                 .isGooglePlayServicesAvailable(mAppContext) == ConnectionResult.SUCCESS;
     59         if (!isPlayServicesAvailable) {
     60             throw new IllegalStateException("Google Play Services not available");
     61         }
     62         mDispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(mAppContext));
     63         mJobConverter = new FirebaseJobConverter(mDispatcher);
     64     }
     65 
     66     @Override
     67     public void schedule(WorkSpec... workSpecs) {
     68         for (WorkSpec workSpec : workSpecs) {
     69             if (workSpec.calculateNextRunTime() > System.currentTimeMillis()) {
     70                 scheduleLater(workSpec);
     71             } else {
     72                 scheduleNow(workSpec);
     73             }
     74         }
     75     }
     76 
     77     @Override
     78     public void cancel(@NonNull String workSpecId) {
     79         mDispatcher.cancel(workSpecId);
     80     }
     81 
     82     void scheduleNow(WorkSpec workSpec) {
     83         Job job = mJobConverter.convert(workSpec);
     84         Log.d(TAG, String.format("Scheduling work now, ID: %s", workSpec.id));
     85         int result = mDispatcher.schedule(job);
     86         if (result != FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS) {
     87             Log.e(TAG, String.format("Schedule failed. Result = %s", result));
     88         }
     89     }
     90 
     91     private void scheduleLater(WorkSpec workSpec) {
     92         if (mAlarmManager == null) {
     93             mAlarmManager = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);
     94         }
     95         if (mIdGenerator == null) {
     96             mIdGenerator = new IdGenerator(mAppContext);
     97         }
     98         Log.d(TAG, String.format("Scheduling work later, ID: %s", workSpec.id));
     99         PendingIntent pendingIntent = createScheduleLaterPendingIntent(workSpec);
    100 
    101         // This wakes up the device at exactly the next run time.
    102         // A wakeup is necessary because the device could be sleeping when this alarm is fired.
    103         long triggerAtMillis = workSpec.calculateNextRunTime();
    104         if (Build.VERSION.SDK_INT >= 19) {
    105             mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
    106         } else {
    107             mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
    108         }
    109     }
    110 
    111     private PendingIntent createScheduleLaterPendingIntent(WorkSpec workSpec) {
    112         Intent intent = new Intent(mAppContext, FirebaseDelayedJobAlarmReceiver.class);
    113         intent.putExtra(FirebaseDelayedJobAlarmReceiver.WORKSPEC_ID_KEY, workSpec.id);
    114         int requestCode = mIdGenerator.nextFirebaseAlarmId();
    115         return PendingIntent.getBroadcast(mAppContext, requestCode, intent, 0);
    116     }
    117 }
    118