Repo cloned
This commit is contained in:
commit
496ae75f58
7988 changed files with 1451097 additions and 0 deletions
11
core-gms/tasks/build.gradle.kts
Normal file
11
core-gms/tasks/build.gradle.kts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
plugins {
|
||||
id("signal-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.google.android.gms.tasks"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core-gms:base"))
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@Keep
|
||||
public abstract class CancellationToken {
|
||||
|
||||
public abstract boolean isCancellationRequested();
|
||||
|
||||
@NonNull
|
||||
public abstract CancellationToken onCanceledRequested(@NonNull OnTokenCanceledListener listener);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@Keep
|
||||
public interface Continuation<TResult, TContinuationResult> {
|
||||
TContinuationResult then(@NonNull Task<TResult> task) throws Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@Keep
|
||||
public final class DuplicateTaskCompletionException extends IllegalStateException {
|
||||
|
||||
private DuplicateTaskCompletionException(String message, @Nullable Exception cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static IllegalStateException of(@NonNull Task<?> task) {
|
||||
if (!task.isComplete()) {
|
||||
return new IllegalStateException("Task is not complete.");
|
||||
}
|
||||
|
||||
final String description;
|
||||
if (task.getException() != null) {
|
||||
description = "failure";
|
||||
} else if (task.isSuccessful()) {
|
||||
description = "success";
|
||||
} else if (task.isCanceled()) {
|
||||
description = "cancellation";
|
||||
} else {
|
||||
description = "unknown state";
|
||||
}
|
||||
|
||||
return new DuplicateTaskCompletionException(
|
||||
"Already completed: " + description, task.getException()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public interface OnCanceledListener {
|
||||
void onCanceled();
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public interface OnCompleteListener<TResult> {
|
||||
void onComplete(Task<TResult> task);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@Keep
|
||||
public interface OnFailureListener {
|
||||
void onFailure(@NonNull Exception e);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public interface OnSuccessListener<TResult> {
|
||||
void onSuccess(TResult result);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public interface OnTokenCanceledListener {
|
||||
void onCanceled();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public class RuntimeExecutionException extends RuntimeException {
|
||||
public RuntimeExecutionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@Keep
|
||||
public interface SuccessContinuation<TResult, TContinuationResult> {
|
||||
@NonNull
|
||||
Task<TContinuationResult> then(TResult result) throws Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Keep
|
||||
public abstract class Task<TResult> {
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCanceledListener(@NonNull OnCanceledListener listener) {
|
||||
throw new UnsupportedOperationException("addOnCanceledListener is not implemented.");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCanceledListener(@NonNull Activity activity, @NonNull OnCanceledListener listener) {
|
||||
throw new UnsupportedOperationException("addOnCanceledListener is not implemented.");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCanceledListener(@NonNull Executor executor, @NonNull OnCanceledListener listener) {
|
||||
throw new UnsupportedOperationException("addOnCanceledListener is not implemented.");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCompleteListener(@NonNull OnCompleteListener<TResult> listener) {
|
||||
throw new UnsupportedOperationException("addOnCompleteListener is not implemented");
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCompleteListener(@NonNull Activity activity, @NonNull OnCompleteListener<TResult> listener) {
|
||||
throw new UnsupportedOperationException("addOnCompleteListener is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Task<TResult> addOnCompleteListener(@NonNull Executor executor, @NonNull OnCompleteListener<TResult> listener) {
|
||||
throw new UnsupportedOperationException("addOnCompleteListener is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnFailureListener(@NonNull OnFailureListener listener);
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnFailureListener(@NonNull Activity activity, @NonNull OnFailureListener listener);
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnFailureListener(@NonNull Executor executor, @NonNull OnFailureListener listener);
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnSuccessListener(@NonNull OnSuccessListener<? super TResult> listener);
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnSuccessListener(@NonNull Activity activity, @NonNull OnSuccessListener<? super TResult> listener);
|
||||
|
||||
@NonNull
|
||||
public abstract Task<TResult> addOnSuccessListener(@NonNull Executor executor, @NonNull OnSuccessListener<? super TResult> listener);
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(@NonNull Continuation<TResult, TContinuationResult> continuation) {
|
||||
throw new UnsupportedOperationException("continueWith is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(@NonNull Executor executor, @NonNull Continuation<TResult, TContinuationResult> continuation) {
|
||||
throw new UnsupportedOperationException("continueWith is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(@NonNull Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
throw new UnsupportedOperationException("continueWithTask is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(@NonNull Executor executor, @NonNull Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
throw new UnsupportedOperationException("continueWithTask is not implemented");
|
||||
}
|
||||
|
||||
public abstract @Nullable Exception getException();
|
||||
|
||||
public abstract TResult getResult();
|
||||
|
||||
public abstract <X extends Throwable> TResult getResult(@NonNull Class<X> exceptionType) throws X;
|
||||
|
||||
public abstract boolean isCanceled();
|
||||
|
||||
public abstract boolean isComplete();
|
||||
|
||||
public abstract boolean isSuccessful();
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(@NonNull SuccessContinuation<TResult, TContinuationResult> successContinuation) {
|
||||
throw new UnsupportedOperationException("onSuccessTask is not implemented");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(@NonNull Executor executor, @NonNull SuccessContinuation<TResult, TContinuationResult> successContinuation) {
|
||||
throw new UnsupportedOperationException("onSuccessTask is not implemented");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import org.microg.gms.tasks.TaskImpl;
|
||||
|
||||
@Keep
|
||||
public class TaskCompletionSource<TResult> {
|
||||
|
||||
private final TaskImpl<TResult> task = new TaskImpl<>();
|
||||
|
||||
public TaskCompletionSource() {}
|
||||
|
||||
public TaskCompletionSource(CancellationToken token) {
|
||||
token.onCanceledRequested(() -> {
|
||||
try {
|
||||
task.cancel();
|
||||
} catch (DuplicateTaskCompletionException ignored) {}
|
||||
});
|
||||
}
|
||||
|
||||
public Task<TResult> getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public void setException(Exception e) {
|
||||
task.setException(e);
|
||||
}
|
||||
|
||||
public void setResult(TResult result) {
|
||||
task.setResult(result);
|
||||
}
|
||||
|
||||
public boolean trySetException(Exception e) {
|
||||
try {
|
||||
setException(e);
|
||||
} catch (DuplicateTaskCompletionException ignored) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean trySetResult(TResult result) {
|
||||
try {
|
||||
setResult(result);
|
||||
} catch (DuplicateTaskCompletionException ignored) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Keep
|
||||
public class TaskExecutors {
|
||||
|
||||
private TaskExecutors() {}
|
||||
|
||||
public static final Executor MAIN_THREAD = new Executor() {
|
||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
if (Looper.getMainLooper() == Looper.myLooper()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
handler.post(runnable);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.google.android.gms.tasks;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.internal.Preconditions;
|
||||
|
||||
import org.microg.gms.tasks.CancellationTokenImpl;
|
||||
import org.microg.gms.tasks.TaskImpl;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@Keep
|
||||
public final class Tasks {
|
||||
|
||||
private Tasks() {}
|
||||
|
||||
public static <TResult> TResult await(@NonNull Task<TResult> task)
|
||||
throws ExecutionException, InterruptedException
|
||||
{
|
||||
Preconditions.checkNotMainThread();
|
||||
Preconditions.checkNotGoogleApiHandlerThread();
|
||||
Preconditions.checkNotNull(task, "Task must not be null");
|
||||
|
||||
if (!task.isComplete()) {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());
|
||||
latch.await();
|
||||
}
|
||||
|
||||
return getResult(task);
|
||||
}
|
||||
|
||||
static <TResult> TResult await(@NonNull Task<TResult> task, long timeout, @NonNull TimeUnit unit)
|
||||
throws ExecutionException, InterruptedException, TimeoutException
|
||||
{
|
||||
Preconditions.checkNotMainThread();
|
||||
Preconditions.checkNotGoogleApiHandlerThread();
|
||||
Preconditions.checkNotNull(task, "Task must not be null");
|
||||
Preconditions.checkNotNull(unit, "TimeUnit must not be null");
|
||||
|
||||
if (!task.isComplete()) {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());
|
||||
boolean completed = latch.await(timeout, unit);
|
||||
if (!completed) {
|
||||
throw new TimeoutException("Timed out waiting for Task");
|
||||
}
|
||||
}
|
||||
|
||||
return getResult(task);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public static <TResult> Task<TResult> call(@NonNull Callable<TResult> callable) {
|
||||
return call(TaskExecutors.MAIN_THREAD, callable);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public static <TResult> Task<TResult> call(@NonNull Executor executor, @NonNull Callable<TResult> callable) {
|
||||
Preconditions.checkNotNull(executor, "Executor must not be null");
|
||||
Preconditions.checkNotNull(callable, "Callback must not be null");
|
||||
|
||||
TaskCompletionSource<TResult> taskSource = new TaskCompletionSource<>();
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
TResult result = callable.call();
|
||||
taskSource.setResult(result);
|
||||
} catch (Exception e) {
|
||||
taskSource.setException(e);
|
||||
} catch (Throwable t) {
|
||||
taskSource.setException(new RuntimeException(t));
|
||||
}
|
||||
});
|
||||
return taskSource.getTask();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <TResult> Task<TResult> forCanceled() {
|
||||
TaskImpl<TResult> task = new TaskImpl<>();
|
||||
task.cancel();
|
||||
return task;
|
||||
}
|
||||
|
||||
public static <TResult> Task<TResult> forException(Exception e) {
|
||||
TaskImpl<TResult> task = new TaskImpl<>();
|
||||
task.setException(e);
|
||||
return task;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <TResult> Task<TResult> forResult(TResult result) {
|
||||
TaskImpl<TResult> task = new TaskImpl<>();
|
||||
task.setResult(result);
|
||||
return task;
|
||||
}
|
||||
|
||||
private static <TResult> TResult getResult(Task<TResult> task) throws ExecutionException {
|
||||
if (task.isSuccessful()) {
|
||||
return task.getResult();
|
||||
}
|
||||
if (task.isCanceled()) {
|
||||
throw new CancellationException("Task is already canceled");
|
||||
}
|
||||
throw new ExecutionException(task.getException());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> Task<T> withTimeout(@NonNull Task<T> task, long timeout, @NonNull TimeUnit unit) {
|
||||
Preconditions.checkNotNull(task, "Task must not be null");
|
||||
Preconditions.checkArgument(timeout > 0L, "Timeout must be positive");
|
||||
Preconditions.checkNotNull(unit, "TimeUnit must not be null");
|
||||
|
||||
final CancellationTokenImpl cancellationToken = new CancellationTokenImpl();
|
||||
final TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<>(cancellationToken);
|
||||
|
||||
final Handler handler = new Handler(Looper.getMainLooper());
|
||||
final Runnable timeoutRunnable = () ->
|
||||
taskCompletionSource.trySetException(new TimeoutException());
|
||||
|
||||
handler.postDelayed(timeoutRunnable, unit.toMillis(timeout));
|
||||
|
||||
task.addOnCompleteListener(completedTask -> {
|
||||
handler.removeCallbacks(timeoutRunnable);
|
||||
|
||||
if (completedTask.isSuccessful()) {
|
||||
taskCompletionSource.trySetResult(completedTask.getResult());
|
||||
} else if (completedTask.isCanceled()) {
|
||||
cancellationToken.cancel();
|
||||
} else {
|
||||
taskCompletionSource.trySetException(completedTask.getException());
|
||||
}
|
||||
});
|
||||
|
||||
return taskCompletionSource.getTask();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.CancellationToken;
|
||||
import com.google.android.gms.tasks.DuplicateTaskCompletionException;
|
||||
import com.google.android.gms.tasks.OnTokenCanceledListener;
|
||||
|
||||
public class CancellationTokenImpl extends CancellationToken {
|
||||
private TaskImpl<Void> task = new TaskImpl<>();
|
||||
|
||||
@Override
|
||||
public boolean isCancellationRequested() {
|
||||
return task.isComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CancellationToken onCanceledRequested(OnTokenCanceledListener listener) {
|
||||
task.addOnSuccessListener(aVoid -> listener.onCanceled());
|
||||
return this;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
task.cancel();
|
||||
} catch (DuplicateTaskCompletionException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.OnCanceledListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class CancelledExecutor<TResult> extends UpdateExecutor<TResult> {
|
||||
private OnCanceledListener listener;
|
||||
|
||||
public CancelledExecutor(Executor executor, OnCanceledListener listener) {
|
||||
super(executor);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isCanceled()) {
|
||||
execute(() -> listener.onCanceled());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class CompletedExecutor<TResult> extends UpdateExecutor<TResult> {
|
||||
private OnCompleteListener<TResult> listener;
|
||||
|
||||
public CompletedExecutor(Executor executor, OnCompleteListener<TResult> listener) {
|
||||
super(executor);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isComplete()) {
|
||||
execute(() -> listener.onComplete(task));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.Continuation;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.tasks.TaskCompletionSource;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class ContinuationExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {
|
||||
private Continuation<TResult, TContinuationResult> continuation;
|
||||
private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();
|
||||
|
||||
public ContinuationExecutor(Executor executor, Continuation<TResult, TContinuationResult> continuation) {
|
||||
super(executor);
|
||||
this.continuation = continuation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isComplete()) {
|
||||
execute(() -> {
|
||||
try {
|
||||
completionSource.setResult(continuation.then(task));
|
||||
} catch (Exception e) {
|
||||
completionSource.setException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Task<TContinuationResult> getTask() {
|
||||
return completionSource.getTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
continuation = null;
|
||||
completionSource = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.Continuation;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.tasks.TaskCompletionSource;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class ContinuationWithExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {
|
||||
private Continuation<TResult, Task<TContinuationResult>> continuation;
|
||||
private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();
|
||||
|
||||
public ContinuationWithExecutor(Executor executor, Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
super(executor);
|
||||
this.continuation = continuation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isComplete()) {
|
||||
execute(() -> {
|
||||
try {
|
||||
continuation.then(task).addOnCompleteListener(this, (subTask) -> {
|
||||
if (subTask.isSuccessful()) {
|
||||
completionSource.setResult(subTask.getResult());
|
||||
} else {
|
||||
completionSource.setException(subTask.getException());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
completionSource.setException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Task<TContinuationResult> getTask() {
|
||||
return completionSource.getTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
continuation = null;
|
||||
completionSource = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.OnFailureListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class FailureExecutor<TResult> extends UpdateExecutor<TResult> {
|
||||
private OnFailureListener listener;
|
||||
|
||||
public FailureExecutor(Executor executor, OnFailureListener listener) {
|
||||
super(executor);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isComplete() && !task.isSuccessful() && !task.isCanceled()) {
|
||||
execute(() -> listener.onFailure(task.getException()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.SuccessContinuation;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.tasks.TaskCompletionSource;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class SuccessContinuationExecutor<TResult, TContinuationResult> extends UpdateExecutor<TResult> {
|
||||
private SuccessContinuation<TResult, TContinuationResult> continuation;
|
||||
private TaskCompletionSource<TContinuationResult> completionSource = new TaskCompletionSource<>();
|
||||
|
||||
public SuccessContinuationExecutor(Executor executor, SuccessContinuation<TResult, TContinuationResult> continuation) {
|
||||
super(executor);
|
||||
this.continuation = continuation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isSuccessful()) {
|
||||
execute(() -> {
|
||||
try {
|
||||
continuation.then(task.getResult()).addOnCompleteListener(this, (subTask) -> {
|
||||
if (subTask.isSuccessful()) {
|
||||
completionSource.setResult(subTask.getResult());
|
||||
} else {
|
||||
completionSource.setException(subTask.getException());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
completionSource.setException(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
completionSource.setException(task.getException());
|
||||
}
|
||||
}
|
||||
|
||||
public Task<TContinuationResult> getTask() {
|
||||
return completionSource.getTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
continuation = null;
|
||||
completionSource = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.OnSuccessListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class SuccessExecutor<TResult> extends UpdateExecutor<TResult> {
|
||||
private OnSuccessListener<? super TResult> listener;
|
||||
|
||||
public SuccessExecutor(Executor executor, OnSuccessListener<? super TResult> listener) {
|
||||
super(executor);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdate(Task<TResult> task) {
|
||||
if (task.isSuccessful()) {
|
||||
execute(() -> listener.onSuccess(task.getResult()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
240
core-gms/tasks/src/main/java/org/microg/gms/tasks/TaskImpl.java
Normal file
240
core-gms/tasks/src/main/java/org/microg/gms/tasks/TaskImpl.java
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.google.android.gms.tasks.Continuation;
|
||||
import com.google.android.gms.tasks.DuplicateTaskCompletionException;
|
||||
import com.google.android.gms.tasks.OnCanceledListener;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.OnFailureListener;
|
||||
import com.google.android.gms.tasks.OnSuccessListener;
|
||||
import com.google.android.gms.tasks.RuntimeExecutionException;
|
||||
import com.google.android.gms.tasks.SuccessContinuation;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import static com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD;
|
||||
|
||||
public class TaskImpl<TResult> extends Task<TResult> {
|
||||
private final Object lock = new Object();
|
||||
private boolean completed;
|
||||
private boolean cancelled;
|
||||
private TResult result;
|
||||
private Exception exception;
|
||||
private Queue<UpdateListener<TResult>> completionQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCanceledListener(OnCanceledListener listener) {
|
||||
return addOnCanceledListener(MAIN_THREAD, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCanceledListener(Executor executor, OnCanceledListener listener) {
|
||||
return enqueueOrInvoke(new CancelledExecutor<>(executor, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCanceledListener(Activity activity, OnCanceledListener listener) {
|
||||
return enqueueOrInvoke(activity, new CancelledExecutor<>(MAIN_THREAD, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCompleteListener(OnCompleteListener<TResult> listener) {
|
||||
return addOnCompleteListener(MAIN_THREAD, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCompleteListener(Executor executor, OnCompleteListener<TResult> listener) {
|
||||
return enqueueOrInvoke(new CompletedExecutor<>(executor, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnCompleteListener(Activity activity, OnCompleteListener<TResult> listener) {
|
||||
return enqueueOrInvoke(activity, new CompletedExecutor<>(MAIN_THREAD, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnFailureListener(OnFailureListener listener) {
|
||||
return addOnFailureListener(MAIN_THREAD, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnFailureListener(Executor executor, OnFailureListener listener) {
|
||||
return enqueueOrInvoke(new FailureExecutor<>(executor, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnFailureListener(Activity activity, OnFailureListener listener) {
|
||||
return enqueueOrInvoke(activity, new FailureExecutor<>(MAIN_THREAD, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnSuccessListener(OnSuccessListener<? super TResult> listener) {
|
||||
return addOnSuccessListener(MAIN_THREAD, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnSuccessListener(Executor executor, OnSuccessListener<? super TResult> listener) {
|
||||
return enqueueOrInvoke(new SuccessExecutor<>(executor, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task<TResult> addOnSuccessListener(Activity activity, OnSuccessListener<? super TResult> listener) {
|
||||
return enqueueOrInvoke(activity, new SuccessExecutor<>(MAIN_THREAD, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(Continuation<TResult, TContinuationResult> continuation) {
|
||||
return continueWith(MAIN_THREAD, continuation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWith(Executor executor, Continuation<TResult, TContinuationResult> continuation) {
|
||||
ContinuationExecutor<TResult, TContinuationResult> c = new ContinuationExecutor<>(executor, continuation);
|
||||
enqueueOrInvoke(c);
|
||||
return c.getTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
return continueWithTask(MAIN_THREAD, continuation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> continueWithTask(Executor executor, Continuation<TResult, Task<TContinuationResult>> continuation) {
|
||||
ContinuationWithExecutor<TResult, TContinuationResult> c = new ContinuationWithExecutor<>(executor, continuation);
|
||||
enqueueOrInvoke(c);
|
||||
return c.getTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getException() {
|
||||
synchronized (lock) {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TResult getResult() {
|
||||
synchronized (lock) {
|
||||
if (!completed) throw new IllegalStateException("Task is not yet complete");
|
||||
if (cancelled) throw new CancellationException("Task is canceled");
|
||||
if (exception != null) throw new RuntimeExecutionException(exception);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X extends Throwable> TResult getResult(Class<X> exceptionType) throws X {
|
||||
synchronized (lock) {
|
||||
if (!completed) throw new IllegalStateException("Task is not yet complete");
|
||||
if (cancelled) throw new CancellationException("Task is canceled");
|
||||
if (exceptionType.isInstance(exception)) throw exceptionType.cast(exception);
|
||||
if (exception != null) throw new RuntimeExecutionException(exception);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
synchronized (lock) {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
synchronized (lock) {
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccessful() {
|
||||
synchronized (lock) {
|
||||
return completed && !cancelled && exception == null;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerActivityStop(Activity activity, UpdateListener<TResult> listener) {
|
||||
UpdateListenerLifecycleObserver.getObserverForActivity(activity).registerActivityStopListener(listener);
|
||||
}
|
||||
|
||||
private Task<TResult> enqueueOrInvoke(Activity activity, UpdateListener<TResult> listener) {
|
||||
synchronized (lock) {
|
||||
if (completed) {
|
||||
listener.onTaskUpdate(this);
|
||||
} else {
|
||||
completionQueue.offer(listener);
|
||||
registerActivityStop(activity, listener);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Task<TResult> enqueueOrInvoke(UpdateListener<TResult> listener) {
|
||||
synchronized (lock) {
|
||||
if (completed) {
|
||||
listener.onTaskUpdate(this);
|
||||
} else {
|
||||
completionQueue.offer(listener);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void notifyQueue() {
|
||||
UpdateListener<TResult> listener;
|
||||
while ((listener = completionQueue.poll()) != null) {
|
||||
listener.onTaskUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (lock) {
|
||||
if (completed) throw DuplicateTaskCompletionException.of(this);
|
||||
this.completed = true;
|
||||
this.cancelled = true;
|
||||
notifyQueue();
|
||||
}
|
||||
}
|
||||
|
||||
public void setResult(TResult result) {
|
||||
synchronized (lock) {
|
||||
if (completed) throw DuplicateTaskCompletionException.of(this);
|
||||
this.completed = true;
|
||||
this.result = result;
|
||||
notifyQueue();
|
||||
}
|
||||
}
|
||||
|
||||
public void setException(Exception exception) {
|
||||
synchronized (lock) {
|
||||
if (completed) throw DuplicateTaskCompletionException.of(this);
|
||||
this.completed = true;
|
||||
this.exception = exception;
|
||||
notifyQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(SuccessContinuation<TResult, TContinuationResult> successContinuation) {
|
||||
return onSuccessTask(MAIN_THREAD, successContinuation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <TContinuationResult> Task<TContinuationResult> onSuccessTask(Executor executor, SuccessContinuation<TResult, TContinuationResult> successContinuation) {
|
||||
SuccessContinuationExecutor<TResult, TContinuationResult> c = new SuccessContinuationExecutor<>(executor, successContinuation);
|
||||
enqueueOrInvoke(c);
|
||||
return c.getTask();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public abstract class UpdateExecutor<TResult> implements UpdateListener<TResult>, Executor {
|
||||
private Executor executor;
|
||||
|
||||
public UpdateExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
if (executor == null) return;
|
||||
executor.execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
executor = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
public interface UpdateListener<TResult> {
|
||||
void onTaskUpdate(Task<TResult> task);
|
||||
|
||||
void cancel();
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.tasks;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class UpdateListenerLifecycleObserver {
|
||||
private static WeakHashMap<Activity, WeakReference<UpdateListenerLifecycleObserver>> map = new WeakHashMap<>();
|
||||
private static boolean activityLifecycleCallbacksRegistered = false;
|
||||
private List<WeakReference<UpdateListener<?>>> list = new ArrayList<>();
|
||||
|
||||
public synchronized static UpdateListenerLifecycleObserver getObserverForActivity(Activity activity) {
|
||||
WeakReference<UpdateListenerLifecycleObserver> ref = map.get(activity);
|
||||
if (ref != null) {
|
||||
UpdateListenerLifecycleObserver observer = ref.get();
|
||||
if (observer != null) {
|
||||
return observer;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activityLifecycleCallbacksRegistered) {
|
||||
activity.getApplication().registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks());
|
||||
activityLifecycleCallbacksRegistered = true;
|
||||
}
|
||||
|
||||
UpdateListenerLifecycleObserver newInstance = new UpdateListenerLifecycleObserver();
|
||||
map.put(activity, new WeakReference<>(newInstance));
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
private UpdateListenerLifecycleObserver() {
|
||||
}
|
||||
|
||||
public synchronized void registerActivityStopListener(UpdateListener<?> listener) {
|
||||
list.add(new WeakReference<>(listener));
|
||||
}
|
||||
|
||||
public synchronized void onStop() {
|
||||
for (WeakReference<UpdateListener<?>> ref : list) {
|
||||
UpdateListener<?> listener = ref.get();
|
||||
listener.cancel();
|
||||
}
|
||||
list.clear();
|
||||
}
|
||||
|
||||
private static class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
WeakReference<UpdateListenerLifecycleObserver> ref = map.get(activity);
|
||||
if (ref != null) {
|
||||
UpdateListenerLifecycleObserver observer = ref.get();
|
||||
if (observer != null) {
|
||||
observer.onStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue