// Copyright 2016 Google, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package com.firebase.jobdispatcher; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.support.annotation.NonNull; import com.firebase.jobdispatcher.FirebaseJobDispatcher.ScheduleResult; /** * GooglePlayDriver provides an implementation of Driver for devices with Google Play * services installed. This backend does not do any availability checks and any uses should be * guarded with a call to {@code GoogleApiAvailability#isGooglePlayServicesAvailable(android.content.Context)} * * @see <a href="https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability#isGooglePlayServicesAvailable(android.content.Context)">GoogleApiAvailability</a> */ public final class GooglePlayDriver implements Driver { static final String BACKEND_PACKAGE = "com.google.android.gms"; private final static String ACTION_SCHEDULE = "com.google.android.gms.gcm.ACTION_SCHEDULE"; private final static String BUNDLE_PARAM_SCHEDULER_ACTION = "scheduler_action"; private final static String BUNDLE_PARAM_TAG = "tag"; private final static String BUNDLE_PARAM_TOKEN = "app"; private final static String BUNDLE_PARAM_COMPONENT = "component"; private final static String SCHEDULER_ACTION_SCHEDULE_TASK = "SCHEDULE_TASK"; private final static String SCHEDULER_ACTION_CANCEL_TASK = "CANCEL_TASK"; private final static String SCHEDULER_ACTION_CANCEL_ALL = "CANCEL_ALL"; private static final String INTENT_PARAM_SOURCE = "source"; private static final String INTENT_PARAM_SOURCE_VERSION = "source_version"; private static final int JOB_DISPATCHER_SOURCE_CODE = 1 << 3; private static final int JOB_DISPATCHER_SOURCE_VERSION_CODE = 1; private final JobValidator mValidator; /** * The application Context. Used to send broadcasts. */ private final Context mContext; /** * A PendingIntent from this package. Passed inside the broadcast so the receiver can verify the * sender's package. */ private final PendingIntent mToken; /** * Turns Jobs into Bundles. */ private final GooglePlayJobWriter mWriter; /** * This is hardcoded to true to avoid putting an unnecessary dependency on the Google Play * services library. */ //TODO: this is an unsatisfying solution private final boolean mAvailable = true; /** * Instantiates a new GooglePlayDriver. */ public GooglePlayDriver(Context context) { mContext = context; mToken = PendingIntent.getBroadcast(context, 0, new Intent(), 0); mWriter = new GooglePlayJobWriter(); mValidator = new DefaultJobValidator(context); } @Override public boolean isAvailable() { return mAvailable; } /** * Schedules the provided Job. */ @Override @ScheduleResult public int schedule(@NonNull Job job) { mContext.sendBroadcast(createScheduleRequest(job)); return FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS; } @Override public int cancel(@NonNull String tag) { mContext.sendBroadcast(createCancelRequest(tag)); return FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS; } @Override public int cancelAll() { mContext.sendBroadcast(createBatchCancelRequest()); return FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS; } @NonNull protected Intent createCancelRequest(@NonNull String tag) { Intent cancelReq = createSchedulerIntent(SCHEDULER_ACTION_CANCEL_TASK); cancelReq.putExtra(BUNDLE_PARAM_TAG, tag); cancelReq.putExtra(BUNDLE_PARAM_COMPONENT, new ComponentName(mContext, getReceiverClass())); return cancelReq; } @NonNull protected Intent createBatchCancelRequest() { Intent cancelReq = createSchedulerIntent(SCHEDULER_ACTION_CANCEL_ALL); cancelReq.putExtra(BUNDLE_PARAM_COMPONENT, new ComponentName(mContext, getReceiverClass())); return cancelReq; } @NonNull protected Class<GooglePlayReceiver> getReceiverClass() { return GooglePlayReceiver.class; } @NonNull @Override public JobValidator getValidator() { return mValidator; } @NonNull private Intent createScheduleRequest(JobParameters job) { Intent scheduleReq = createSchedulerIntent(SCHEDULER_ACTION_SCHEDULE_TASK); scheduleReq.putExtras(mWriter.writeToBundle(job, scheduleReq.getExtras())); return scheduleReq; } @NonNull private Intent createSchedulerIntent(String schedulerAction) { Intent scheduleReq = new Intent(ACTION_SCHEDULE); scheduleReq.setPackage(BACKEND_PACKAGE); scheduleReq.putExtra(BUNDLE_PARAM_SCHEDULER_ACTION, schedulerAction); scheduleReq.putExtra(BUNDLE_PARAM_TOKEN, mToken); scheduleReq.putExtra(INTENT_PARAM_SOURCE, JOB_DISPATCHER_SOURCE_CODE); scheduleReq.putExtra(INTENT_PARAM_SOURCE_VERSION, JOB_DISPATCHER_SOURCE_VERSION_CODE); return scheduleReq; } }