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 
SynchronousResultReceiver()47     public SynchronousResultReceiver() {
48         super((Handler) null);
49     }
50 
51     @Override
onReceiveResult(int resultCode, Bundle resultData)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      */
awaitResult(long timeoutMillis)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