Skip to content

Commit

Permalink
Merge pull request #5617 from loki666:workmanager
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 248533906
  • Loading branch information
ojw28 committed May 20, 2019
2 parents 835d1f3 + 6c5a39a commit 92532d3
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 0 deletions.
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
([#5784](https://github.com/google/ExoPlayer/issues/5784)).
* Add a workaround for broken raw audio decoding on Oppo R9
([#5782](https://github.com/google/ExoPlayer/issues/5782)).
* Offline: Add Scheduler implementation which uses WorkManager.

### 2.10.1 ###

Expand Down
2 changes: 2 additions & 0 deletions core_settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ include modulePrefix + 'extension-vp9'
include modulePrefix + 'extension-rtmp'
include modulePrefix + 'extension-leanback'
include modulePrefix + 'extension-jobdispatcher'
include modulePrefix + 'extension-workmanager'

project(modulePrefix + 'library').projectDir = new File(rootDir, 'library/all')
project(modulePrefix + 'library-core').projectDir = new File(rootDir, 'library/core')
Expand All @@ -60,3 +61,4 @@ project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensio
project(modulePrefix + 'extension-rtmp').projectDir = new File(rootDir, 'extensions/rtmp')
project(modulePrefix + 'extension-leanback').projectDir = new File(rootDir, 'extensions/leanback')
project(modulePrefix + 'extension-jobdispatcher').projectDir = new File(rootDir, 'extensions/jobdispatcher')
project(modulePrefix + 'extension-workmanager').projectDir = new File(rootDir, 'extensions/workmanager')
22 changes: 22 additions & 0 deletions extensions/workmanager/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ExoPlayer WorkManager extension

This extension provides a Scheduler implementation which uses [WorkManager][].

[WorkManager]: https://developer.android.com/topic/libraries/architecture/workmanager.html

## Getting the extension

The easiest way to use the extension is to add it as a gradle dependency:

```gradle
implementation 'com.google.android.exoplayer:extension-workmanager:2.X.X'
```

where `2.X.X` is the version, which must match the version of the ExoPlayer
library being used.

Alternatively, you can clone the ExoPlayer repository and depend on the module
locally. Instructions for doing this can be found in ExoPlayer's
[top level README][].

[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md
49 changes: 49 additions & 0 deletions extensions/workmanager/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2019 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.
*/
apply from: '../../constants.gradle'
apply plugin: 'com.android.library'

android {
compileSdkVersion project.ext.compileSdkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}

testOptions.unitTests.includeAndroidResources = true
}

dependencies {
implementation project(modulePrefix + 'library-core')
implementation 'androidx.work:work-runtime:2.0.1'
}

ext {
javadocTitle = 'WorkManager extension'
}
apply from: '../../javadoc_library.gradle'

ext {
releaseArtifact = 'extension-workmanager'
releaseDescription = 'WorkManager extension for ExoPlayer.'
}
apply from: '../../publish.gradle'
18 changes: 18 additions & 0 deletions extensions/workmanager/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 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.
-->

<manifest package="com.google.android.exoplayer2.ext.workmanager"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright (C) 2019 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 com.google.android.exoplayer2.ext.workmanager;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.Scheduler;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;

/** A {@link Scheduler} that uses {@link WorkManager}. */
public final class WorkManagerScheduler implements Scheduler {

private static final boolean DEBUG = false;
private static final String TAG = "WorkManagerScheduler";
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 final String workName;

/**
* @param workName A name for work scheduled by this instance. If the same name 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.
*/
public WorkManagerScheduler(String workName) {
this.workName = workName;
}

@Override
public boolean schedule(Requirements requirements, String servicePackage, String serviceAction) {
Constraints constraints = buildConstraints(requirements);
Data inputData = buildInputData(requirements, servicePackage, serviceAction);
OneTimeWorkRequest workRequest = buildWorkRequest(constraints, inputData);
logd("Scheduling work: " + workName);
WorkManager.getInstance().enqueueUniqueWork(workName, ExistingWorkPolicy.REPLACE, workRequest);
return true;
}

@Override
public boolean cancel() {
logd("Canceling work: " + workName);
WorkManager.getInstance().cancelUniqueWork(workName);
return true;
}

private static Constraints buildConstraints(Requirements requirements) {
Constraints.Builder builder = new Constraints.Builder();

if (requirements.isUnmeteredNetworkRequired()) {
builder.setRequiredNetworkType(NetworkType.UNMETERED);
} else if (requirements.isNetworkRequired()) {
builder.setRequiredNetworkType(NetworkType.CONNECTED);
} else {
builder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
}

if (requirements.isChargingRequired()) {
builder.setRequiresCharging(true);
}

if (requirements.isIdleRequired() && Util.SDK_INT >= 23) {
setRequiresDeviceIdle(builder);
}

return builder.build();
}

@TargetApi(23)
private static void setRequiresDeviceIdle(Constraints.Builder builder) {
builder.setRequiresDeviceIdle(true);
}

private static Data buildInputData(
Requirements requirements, String servicePackage, String serviceAction) {
Data.Builder builder = new Data.Builder();

builder.putInt(KEY_REQUIREMENTS, requirements.getRequirements());
builder.putString(KEY_SERVICE_PACKAGE, servicePackage);
builder.putString(KEY_SERVICE_ACTION, serviceAction);

return builder.build();
}

private static OneTimeWorkRequest buildWorkRequest(Constraints constraints, Data inputData) {
OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(SchedulerWorker.class);

builder.setConstraints(constraints);
builder.setInputData(inputData);

return builder.build();
}

private static void logd(String message) {
if (DEBUG) {
Log.d(TAG, message);
}
}

/** A {@link Worker} that starts the target service if the requirements are met. */
// This class needs to be public so that WorkManager can instantiate it.
public static final class SchedulerWorker extends Worker {

private final WorkerParameters workerParams;
private final Context context;

public SchedulerWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
this.workerParams = workerParams;
this.context = context;
}

@Override
public Result doWork() {
logd("SchedulerWorker is started");
Data inputData = workerParams.getInputData();
Assertions.checkNotNull(inputData, "Work started without input data.");
Requirements requirements = new Requirements(inputData.getInt(KEY_REQUIREMENTS, 0));
if (requirements.checkRequirements(context)) {
logd("Requirements are met");
String serviceAction = inputData.getString(KEY_SERVICE_ACTION);
String servicePackage = inputData.getString(KEY_SERVICE_PACKAGE);
Assertions.checkNotNull(serviceAction, "Service action missing.");
Assertions.checkNotNull(servicePackage, "Service package missing.");
Intent intent = new Intent(serviceAction).setPackage(servicePackage);
logd("Starting service action: " + serviceAction + " package: " + servicePackage);
Util.startForegroundService(context, intent);
return Result.success();
} else {
logd("Requirements are not met");
return Result.retry();
}
}
}
}

0 comments on commit 92532d3

Please sign in to comment.