Repo cloned

This commit is contained in:
Fr4nz D13trich 2025-12-29 13:18:34 +01:00
commit 496ae75f58
7988 changed files with 1451097 additions and 0 deletions

View file

@ -0,0 +1,11 @@
plugins {
id("signal-library")
}
android {
namespace = "com.google.android.gms.tasks"
}
dependencies {
implementation(project(":core-gms:base"))
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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()
);
}
}

View file

@ -0,0 +1,8 @@
package com.google.android.gms.tasks;
import androidx.annotation.Keep;
@Keep
public interface OnCanceledListener {
void onCanceled();
}

View file

@ -0,0 +1,8 @@
package com.google.android.gms.tasks;
import androidx.annotation.Keep;
@Keep
public interface OnCompleteListener<TResult> {
void onComplete(Task<TResult> task);
}

View file

@ -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);
}

View file

@ -0,0 +1,8 @@
package com.google.android.gms.tasks;
import androidx.annotation.Keep;
@Keep
public interface OnSuccessListener<TResult> {
void onSuccess(TResult result);
}

View file

@ -0,0 +1,8 @@
package com.google.android.gms.tasks;
import androidx.annotation.Keep;
@Keep
public interface OnTokenCanceledListener {
void onCanceled();
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
};
}

View file

@ -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();
}
}

View file

@ -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) {
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View 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();
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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) {
}
}
}