public final class

PlatformScheduler

extends java.lang.Object

implements Scheduler

 java.lang.Object

↳androidx.media3.exoplayer.scheduler.PlatformScheduler

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-exoplayer', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-exoplayer
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-exoplayer:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

A Scheduler that uses . To use this scheduler, you must add PlatformScheduler.PlatformSchedulerService to your manifest:

 
 

 
 

Summary

Constructors
publicPlatformScheduler(Context context, int jobId)

Methods
public booleancancel()

public RequirementsgetSupportedRequirements(Requirements requirements)

public booleanschedule(Requirements requirements, java.lang.String servicePackage, java.lang.String serviceAction)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public PlatformScheduler(Context context, int jobId)

Parameters:

context: Any context.
jobId: An identifier for the jobs scheduled by this instance. If the same identifier was used by a previous instance, anything scheduled by the previous instance will be canceled by this instance if PlatformScheduler.schedule(Requirements, String, String) or PlatformScheduler.cancel() are called.

Methods

public boolean schedule(Requirements requirements, java.lang.String servicePackage, java.lang.String serviceAction)

public boolean cancel()

public Requirements getSupportedRequirements(Requirements requirements)

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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 androidx.media3.exoplayer.scheduler;

import static androidx.media3.common.util.Assertions.checkNotNull;

import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.PersistableBundle;
import androidx.annotation.RequiresPermission;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;

/**
 * A {@link Scheduler} that uses {@link JobScheduler}. To use this scheduler, you must add {@link
 * PlatformSchedulerService} to your manifest:
 *
 * <pre>{@literal
 * <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 * <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 *
 * <service android:name="androidx.media3.exoplayer.scheduler.PlatformScheduler$PlatformSchedulerService"
 *     android:permission="android.permission.BIND_JOB_SERVICE"
 *     android:exported="true"/>
 * }</pre>
 */
@UnstableApi
public final class PlatformScheduler implements Scheduler {

  private static final String TAG = "PlatformScheduler";
  private static final String KEY_SERVICE_ACTION = "service_action";
  private static final String KEY_SERVICE_PACKAGE = "service_package";
  private static final String KEY_REQUIREMENTS = "requirements";
  private static final int SUPPORTED_REQUIREMENTS =
      Requirements.NETWORK
          | Requirements.NETWORK_UNMETERED
          | Requirements.DEVICE_IDLE
          | Requirements.DEVICE_CHARGING
          | (Util.SDK_INT >= 26 ? Requirements.DEVICE_STORAGE_NOT_LOW : 0);

  private final int jobId;
  private final ComponentName jobServiceComponentName;
  private final JobScheduler jobScheduler;

  /**
   * @param context Any context.
   * @param jobId An identifier for the jobs scheduled by this instance. If the same identifier was
   *     used by a previous instance, anything scheduled by the previous instance will be canceled
   *     by this instance if {@link #schedule(Requirements, String, String)} or {@link #cancel()}
   *     are called.
   */
  @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
  public PlatformScheduler(Context context, int jobId) {
    context = context.getApplicationContext();
    this.jobId = jobId;
    jobServiceComponentName = new ComponentName(context, PlatformSchedulerService.class);
    jobScheduler =
        checkNotNull((JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE));
  }

  @Override
  public boolean schedule(Requirements requirements, String servicePackage, String serviceAction) {
    JobInfo jobInfo =
        buildJobInfo(jobId, jobServiceComponentName, requirements, serviceAction, servicePackage);
    int result = jobScheduler.schedule(jobInfo);
    return result == JobScheduler.RESULT_SUCCESS;
  }

  @Override
  public boolean cancel() {
    jobScheduler.cancel(jobId);
    return true;
  }

  @Override
  public Requirements getSupportedRequirements(Requirements requirements) {
    return requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
  }

  // @RequiresPermission constructor annotation should ensure the permission is present.
  @SuppressWarnings("MissingPermission")
  private static JobInfo buildJobInfo(
      int jobId,
      ComponentName jobServiceComponentName,
      Requirements requirements,
      String serviceAction,
      String servicePackage) {
    Requirements filteredRequirements = requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
    if (!filteredRequirements.equals(requirements)) {
      Log.w(
          TAG,
          "Ignoring unsupported requirements: "
              + (filteredRequirements.getRequirements() ^ requirements.getRequirements()));
    }

    JobInfo.Builder builder = new JobInfo.Builder(jobId, jobServiceComponentName);
    if (requirements.isUnmeteredNetworkRequired()) {
      builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
    } else if (requirements.isNetworkRequired()) {
      builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
    }
    builder.setRequiresDeviceIdle(requirements.isIdleRequired());
    builder.setRequiresCharging(requirements.isChargingRequired());
    if (Util.SDK_INT >= 26 && requirements.isStorageNotLowRequired()) {
      builder.setRequiresStorageNotLow(true);
    }
    builder.setPersisted(true);

    PersistableBundle extras = new PersistableBundle();
    extras.putString(KEY_SERVICE_ACTION, serviceAction);
    extras.putString(KEY_SERVICE_PACKAGE, servicePackage);
    extras.putInt(KEY_REQUIREMENTS, requirements.getRequirements());
    builder.setExtras(extras);

    return builder.build();
  }

  /** A {@link JobService} that starts the target service if the requirements are met. */
  public static final class PlatformSchedulerService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
      PersistableBundle extras = params.getExtras();
      Requirements requirements = new Requirements(extras.getInt(KEY_REQUIREMENTS));
      int notMetRequirements = requirements.getNotMetRequirements(this);
      if (notMetRequirements == 0) {
        String serviceAction = checkNotNull(extras.getString(KEY_SERVICE_ACTION));
        String servicePackage = checkNotNull(extras.getString(KEY_SERVICE_PACKAGE));
        Intent intent = new Intent(serviceAction).setPackage(servicePackage);
        Util.startForegroundService(this, intent);
      } else {
        Log.w(TAG, "Requirements not met: " + notMetRequirements);
        jobFinished(params, /* wantsReschedule= */ true);
      }
      return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
      return false;
    }
  }
}