1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bedstead.remoteframeworkclasses; 18 19 import android.accounts.AccountManagerFuture; 20 import android.accounts.AuthenticatorException; 21 import android.accounts.OperationCanceledException; 22 23 import java.io.IOException; 24 import java.util.concurrent.CountDownLatch; 25 import java.util.concurrent.TimeUnit; 26 import java.util.concurrent.atomic.AtomicReference; 27 28 /** 29 * A simple implementation of {@link AccountManagerFuture} for use with remote calls. 30 * 31 * @param <V> The wrapped future result. 32 */ 33 public final class SimpleAccountManagerFuture<V> implements AccountManagerFuture<V> { 34 35 private final CountDownLatch mIsDone = new CountDownLatch(1); 36 private final AtomicReference<Throwable> mException = new AtomicReference<>(); 37 private final AtomicReference<V> mValue = new AtomicReference<>(); 38 39 @Override cancel(boolean mayInterruptIfRunning)40 public boolean cancel(boolean mayInterruptIfRunning) { 41 // Remote calls cannot cancel futures 42 return false; 43 } 44 45 @Override isCancelled()46 public boolean isCancelled() { 47 return false; 48 } 49 50 @Override isDone()51 public boolean isDone() { 52 return mIsDone.getCount() < 1; 53 } 54 55 @Override getResult()56 public V getResult() throws OperationCanceledException, IOException, AuthenticatorException { 57 try { 58 mIsDone.await(); 59 } catch (InterruptedException e) { 60 throw new RuntimeException("Interrupted while waiting for result", e); 61 } 62 63 Throwable exception = mException.get(); 64 if (exception == null) { 65 return mValue.get(); 66 } else if (exception instanceof OperationCanceledException) { 67 throw (OperationCanceledException) exception; 68 } else if (exception instanceof IOException) { 69 throw (IOException) exception; 70 } else if (exception instanceof AuthenticatorException) { 71 throw (AuthenticatorException) exception; 72 } else { 73 throw new RuntimeException("Unexpected exception type", exception); 74 } 75 } 76 77 /** Set the result of this future. */ setResult(V result)78 public void setResult(V result) { 79 mValue.set(result); 80 mIsDone.countDown(); 81 } 82 83 @Override getResult(long timeout, TimeUnit unit)84 public V getResult(long timeout, TimeUnit unit) 85 throws OperationCanceledException, IOException, AuthenticatorException { 86 try { 87 mIsDone.await(timeout, unit); 88 } catch (InterruptedException e) { 89 throw new RuntimeException("Interrupted while waiting for result", e); 90 } 91 92 Throwable exception = mException.get(); 93 if (exception == null) { 94 return mValue.get(); 95 } else if (exception instanceof OperationCanceledException) { 96 throw (OperationCanceledException) exception; 97 } else if (exception instanceof IOException) { 98 throw (IOException) exception; 99 } else if (exception instanceof AuthenticatorException) { 100 throw (AuthenticatorException) exception; 101 } else { 102 throw new RuntimeException("Unexpected exception type", exception); 103 } 104 } 105 106 /** Set an exception thrown by this future. */ setException(Throwable throwable)107 public void setException(Throwable throwable) { 108 mException.set(throwable); 109 mIsDone.countDown(); 110 } 111 } 112