1 /*
2  * Copyright (C) 2016 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.voicemail.impl.sync;
18 
19 import android.annotation.TargetApi;
20 import android.net.Network;
21 import android.os.Build.VERSION_CODES;
22 import android.support.annotation.NonNull;
23 import android.telecom.PhoneAccountHandle;
24 import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper;
25 import com.android.voicemail.impl.VoicemailStatus;
26 import com.android.voicemail.impl.VvmLog;
27 import java.io.Closeable;
28 import java.util.concurrent.CompletableFuture;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.Future;
31 
32 /**
33  * Class to retrieve a {@link Network} synchronously. {@link #getNetwork(OmtpVvmCarrierConfigHelper,
34  * PhoneAccountHandle)} will block until a suitable network is retrieved or it has failed.
35  */
36 @TargetApi(VERSION_CODES.O)
37 public class VvmNetworkRequest {
38 
39   private static final String TAG = "VvmNetworkRequest";
40 
41   /**
42    * A wrapper around a Network returned by a {@link VvmNetworkRequestCallback}, which should be
43    * closed once not needed anymore.
44    */
45   public static class NetworkWrapper implements Closeable {
46 
47     private final Network network;
48     private final VvmNetworkRequestCallback callback;
49 
NetworkWrapper(Network network, VvmNetworkRequestCallback callback)50     private NetworkWrapper(Network network, VvmNetworkRequestCallback callback) {
51       this.network = network;
52       this.callback = callback;
53     }
54 
get()55     public Network get() {
56       return network;
57     }
58 
59     @Override
close()60     public void close() {
61       callback.releaseNetwork();
62     }
63   }
64 
65   public static class RequestFailedException extends Exception {
66 
RequestFailedException(Throwable cause)67     private RequestFailedException(Throwable cause) {
68       super(cause);
69     }
70   }
71 
72   @NonNull
getNetwork( OmtpVvmCarrierConfigHelper config, PhoneAccountHandle handle, VoicemailStatus.Editor status)73   public static NetworkWrapper getNetwork(
74       OmtpVvmCarrierConfigHelper config, PhoneAccountHandle handle, VoicemailStatus.Editor status)
75       throws RequestFailedException {
76     FutureNetworkRequestCallback callback =
77         new FutureNetworkRequestCallback(config, handle, status);
78     callback.requestNetwork();
79     try {
80       return callback.getFuture().get();
81     } catch (InterruptedException | ExecutionException e) {
82       callback.releaseNetwork();
83       VvmLog.e(TAG, "can't get future network", e);
84       throw new RequestFailedException(e);
85     }
86   }
87 
88   private static class FutureNetworkRequestCallback extends VvmNetworkRequestCallback {
89 
90     /**
91      * {@link CompletableFuture#get()} will block until {@link CompletableFuture# complete(Object) }
92      * has been called on the other thread.
93      */
94     private final CompletableFuture<NetworkWrapper> future = new CompletableFuture<>();
95 
FutureNetworkRequestCallback( OmtpVvmCarrierConfigHelper config, PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status)96     public FutureNetworkRequestCallback(
97         OmtpVvmCarrierConfigHelper config,
98         PhoneAccountHandle phoneAccount,
99         VoicemailStatus.Editor status) {
100       super(config, phoneAccount, status);
101     }
102 
getFuture()103     public Future<NetworkWrapper> getFuture() {
104       return future;
105     }
106 
107     @Override
onAvailable(Network network)108     public void onAvailable(Network network) {
109       super.onAvailable(network);
110       future.complete(new NetworkWrapper(network, this));
111     }
112 
113     @Override
onFailed(String reason)114     public void onFailed(String reason) {
115       super.onFailed(reason);
116       future.complete(null);
117     }
118   }
119 }
120