1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package android.os; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 21 import java.util.concurrent.CompletableFuture; 22 import java.util.concurrent.ExecutionException; 23 import java.util.concurrent.TimeUnit; 24 import java.util.concurrent.TimeoutException; 25 26 /** 27 * Extends ResultReceiver to allow the server end of the ResultReceiver to synchronously wait 28 * on the response from the client. This enables an RPC like system but with the ability to 29 * timeout and discard late results. 30 * 31 * NOTE: Can only be used for one response. Subsequent responses on the same instance are ignored. 32 * {@hide} 33 */ 34 public class SynchronousResultReceiver extends ResultReceiver { 35 public static class Result { 36 public int resultCode; 37 @Nullable public Bundle bundle; 38 39 public Result(int resultCode, @Nullable Bundle bundle) { 40 this.resultCode = resultCode; 41 this.bundle = bundle; 42 } 43 } 44 45 private final CompletableFuture<Result> mFuture = new CompletableFuture<>(); 46 47 public SynchronousResultReceiver() { 48 super((Handler) null); 49 } 50 51 @Override 52 final protected void onReceiveResult(int resultCode, Bundle resultData) { 53 super.onReceiveResult(resultCode, resultData); 54 mFuture.complete(new Result(resultCode, resultData)); 55 } 56 57 /** 58 * Blocks waiting for the result from the remote client. 59 * 60 * @return the Result 61 * @throws TimeoutException if the timeout in milliseconds expired. 62 */ 63 public @NonNull Result awaitResult(long timeoutMillis) throws TimeoutException { 64 final long deadline = System.currentTimeMillis() + timeoutMillis; 65 while (timeoutMillis >= 0) { 66 try { 67 return mFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); 68 } catch (ExecutionException e) { 69 // This will NEVER happen. 70 throw new AssertionError("Error receiving response", e); 71 } catch (InterruptedException e) { 72 // The thread was interrupted, try and get the value again, this time 73 // with the remaining time until the deadline. 74 timeoutMillis -= deadline - System.currentTimeMillis(); 75 } 76 } 77 throw new TimeoutException(); 78 } 79 80 } 81