RemoteWorkManagerImpl.java
/*
* Copyright 2020 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.work.multiprocess;
import static androidx.work.multiprocess.ListenableCallback.ListenableCallbackRunnable.reportFailure;
import android.content.Context;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.work.Operation;
import androidx.work.WorkInfo;
import androidx.work.WorkRequest;
import androidx.work.impl.WorkContinuationImpl;
import androidx.work.impl.WorkDatabase;
import androidx.work.impl.WorkManagerImpl;
import androidx.work.impl.utils.WorkProgressUpdater;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
import androidx.work.multiprocess.parcelable.ParcelConverters;
import androidx.work.multiprocess.parcelable.ParcelableUpdateRequest;
import androidx.work.multiprocess.parcelable.ParcelableWorkContinuationImpl;
import androidx.work.multiprocess.parcelable.ParcelableWorkInfos;
import androidx.work.multiprocess.parcelable.ParcelableWorkQuery;
import androidx.work.multiprocess.parcelable.ParcelableWorkRequests;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executor;
/**
* The implementation of a subset of WorkManager APIs that are safe to be supported across
* processes.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class RemoteWorkManagerImpl extends IWorkManagerImpl.Stub {
// Synthetic access
static byte[] sEMPTY = new byte[0];
private final WorkManagerImpl mWorkManager;
RemoteWorkManagerImpl(@NonNull Context context) {
mWorkManager = WorkManagerImpl.getInstance(context);
}
@Override
@MainThread
public void enqueueWorkRequests(
final @NonNull byte[] request,
final @NonNull IWorkManagerImplCallback callback) {
try {
ParcelableWorkRequests parcelledRequests =
ParcelConverters.unmarshall(request, ParcelableWorkRequests.CREATOR);
List<WorkRequest> workRequests = parcelledRequests.getRequests();
final Operation operation = mWorkManager.enqueue(workRequests);
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void enqueueContinuation(
final @NonNull byte[] request,
final @NonNull IWorkManagerImplCallback callback) {
try {
ParcelableWorkContinuationImpl parcelledRequest =
ParcelConverters.unmarshall(request, ParcelableWorkContinuationImpl.CREATOR);
WorkContinuationImpl continuation =
parcelledRequest.toWorkContinuationImpl(mWorkManager);
final Operation operation = continuation.enqueue();
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void cancelWorkById(@NonNull String id, @NonNull IWorkManagerImplCallback callback) {
try {
final Operation operation = mWorkManager.cancelWorkById(UUID.fromString(id));
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void cancelAllWorkByTag(
@NonNull String tag,
@NonNull IWorkManagerImplCallback callback) {
try {
final Operation operation = mWorkManager.cancelAllWorkByTag(tag);
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void cancelUniqueWork(
@NonNull String name,
@NonNull IWorkManagerImplCallback callback) {
try {
final Operation operation = mWorkManager.cancelUniqueWork(name);
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void cancelAllWork(@NonNull IWorkManagerImplCallback callback) {
try {
final Operation operation = mWorkManager.cancelAllWork();
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableCallback<Operation.State.SUCCESS> listenableCallback =
new ListenableCallback<Operation.State.SUCCESS>(executor, callback,
operation.getResult()) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Operation.State.SUCCESS result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void queryWorkInfo(@NonNull byte[] request, @NonNull IWorkManagerImplCallback callback) {
try {
ParcelableWorkQuery parcelled =
ParcelConverters.unmarshall(request, ParcelableWorkQuery.CREATOR);
final Executor executor = mWorkManager.getWorkTaskExecutor().getBackgroundExecutor();
final ListenableFuture<List<WorkInfo>> future =
mWorkManager.getWorkInfos(parcelled.getWorkQuery());
final ListenableCallback<List<WorkInfo>> listenableCallback =
new ListenableCallback<List<WorkInfo>>(executor, callback, future) {
@NonNull
@Override
public byte[] toByteArray(@NonNull List<WorkInfo> result) {
ParcelableWorkInfos parcelables = new ParcelableWorkInfos(result);
return ParcelConverters.marshall(parcelables);
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
@Override
public void setProgress(@NonNull byte[] request, @NonNull IWorkManagerImplCallback callback) {
try {
ParcelableUpdateRequest parcelled =
ParcelConverters.unmarshall(request, ParcelableUpdateRequest.CREATOR);
final Context context = mWorkManager.getApplicationContext();
final TaskExecutor taskExecutor = mWorkManager.getWorkTaskExecutor();
final Executor executor = taskExecutor.getBackgroundExecutor();
final WorkDatabase database = mWorkManager.getWorkDatabase();
final WorkProgressUpdater progressUpdater =
new WorkProgressUpdater(database, taskExecutor);
final ListenableFuture<Void> future = progressUpdater.updateProgress(
context,
UUID.fromString(parcelled.getId()),
parcelled.getData()
);
final ListenableCallback<Void> listenableCallback =
new ListenableCallback<Void>(executor, callback, future) {
@NonNull
@Override
public byte[] toByteArray(@NonNull Void result) {
return sEMPTY;
}
};
listenableCallback.dispatchCallbackSafely();
} catch (Throwable throwable) {
reportFailure(callback, throwable);
}
}
}