|  | /* | 
|  | * Copyright (C) 2016 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | * use this file except in compliance with the License. You may obtain a copy of | 
|  | * the License at | 
|  | * | 
|  | * http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | * License for the specific language governing permissions and limitations under | 
|  | * the License. | 
|  | */ | 
|  | package android.os; | 
|  |  | 
|  | import android.annotation.NonNull; | 
|  | import android.annotation.Nullable; | 
|  |  | 
|  | import java.util.concurrent.CompletableFuture; | 
|  | import java.util.concurrent.ExecutionException; | 
|  | import java.util.concurrent.TimeUnit; | 
|  | import java.util.concurrent.TimeoutException; | 
|  |  | 
|  | /** | 
|  | * Extends ResultReceiver to allow the server end of the ResultReceiver to synchronously wait | 
|  | * on the response from the client. This enables an RPC like system but with the ability to | 
|  | * timeout and discard late results. | 
|  | * | 
|  | * NOTE: Can only be used for one response. Subsequent responses on the same instance are ignored. | 
|  | * {@hide} | 
|  | */ | 
|  | public class SynchronousResultReceiver extends ResultReceiver { | 
|  | public static class Result { | 
|  | public int resultCode; | 
|  | @Nullable public Bundle bundle; | 
|  |  | 
|  | public Result(int resultCode, @Nullable Bundle bundle) { | 
|  | this.resultCode = resultCode; | 
|  | this.bundle = bundle; | 
|  | } | 
|  | } | 
|  |  | 
|  | private final CompletableFuture<Result> mFuture = new CompletableFuture<>(); | 
|  | private final String mName; | 
|  |  | 
|  | public SynchronousResultReceiver() { | 
|  | super((Handler) null); | 
|  | mName = null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @param name Name for logging purposes | 
|  | */ | 
|  | public SynchronousResultReceiver(String name) { | 
|  | super((Handler) null); | 
|  | mName = name; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | final protected void onReceiveResult(int resultCode, Bundle resultData) { | 
|  | super.onReceiveResult(resultCode, resultData); | 
|  | mFuture.complete(new Result(resultCode, resultData)); | 
|  | } | 
|  |  | 
|  | public String getName() { | 
|  | return mName; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Blocks waiting for the result from the remote client. | 
|  | * | 
|  | * @return the Result | 
|  | * @throws TimeoutException if the timeout in milliseconds expired. | 
|  | */ | 
|  | public @NonNull Result awaitResult(long timeoutMillis) throws TimeoutException { | 
|  | final long deadline = System.currentTimeMillis() + timeoutMillis; | 
|  | while (timeoutMillis >= 0) { | 
|  | try { | 
|  | return mFuture.get(timeoutMillis, TimeUnit.MILLISECONDS); | 
|  | } catch (ExecutionException e) { | 
|  | // This will NEVER happen. | 
|  | throw new AssertionError("Error receiving response", e); | 
|  | } catch (InterruptedException e) { | 
|  | // The thread was interrupted, try and get the value again, this time | 
|  | // with the remaining time until the deadline. | 
|  | timeoutMillis -= deadline - System.currentTimeMillis(); | 
|  | } | 
|  | } | 
|  | throw new TimeoutException(); | 
|  | } | 
|  |  | 
|  | } |