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 Result(int resultCode, @Nullable Bundle bundle)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 private final String mName; 47 SynchronousResultReceiver()48 public SynchronousResultReceiver() { 49 super((Handler) null); 50 mName = null; 51 } 52 53 /** 54 * @param name Name for logging purposes 55 */ SynchronousResultReceiver(String name)56 public SynchronousResultReceiver(String name) { 57 super((Handler) null); 58 mName = name; 59 } 60 61 @Override onReceiveResult(int resultCode, Bundle resultData)62 final protected void onReceiveResult(int resultCode, Bundle resultData) { 63 super.onReceiveResult(resultCode, resultData); 64 mFuture.complete(new Result(resultCode, resultData)); 65 } 66 getName()67 public String getName() { 68 return mName; 69 } 70 71 /** 72 * Blocks waiting for the result from the remote client. 73 * 74 * @return the Result 75 * @throws TimeoutException if the timeout in milliseconds expired. 76 */ awaitResult(long timeoutMillis)77 public @NonNull Result awaitResult(long timeoutMillis) throws TimeoutException { 78 final long deadline = System.currentTimeMillis() + timeoutMillis; 79 while (timeoutMillis >= 0) { 80 try { 81 return mFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); 82 } catch (ExecutionException e) { 83 // This will NEVER happen. 84 throw new AssertionError("Error receiving response", e); 85 } catch (InterruptedException e) { 86 // The thread was interrupted, try and get the value again, this time 87 // with the remaining time until the deadline. 88 timeoutMillis -= deadline - System.currentTimeMillis(); 89 } 90 } 91 throw new TimeoutException(); 92 } 93 94 } 95