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 @SuppressWarnings("AndroidApiChecker") /* CompletableFuture is java8*/
37 @TargetApi(VERSION_CODES.O)
38 public class VvmNetworkRequest {
39 
40   private static final String TAG = "VvmNetworkRequest";
41 
42   /**
43    * A wrapper around a Network returned by a {@link VvmNetworkRequestCallback}, which should be
44    * closed once not needed anymore.
45    */
46   public static class NetworkWrapper implements Closeable {
47 
48     private final Network mNetwork;
49     private final VvmNetworkRequestCallback mCallback;
50 
NetworkWrapper(Network network, VvmNetworkRequestCallback callback)51     private NetworkWrapper(Network network, VvmNetworkRequestCallback callback) {
52       mNetwork = network;
53       mCallback = callback;
54     }
55 
get()56     public Network get() {
57       return mNetwork;
58     }
59 
60     @Override
close()61     public void close() {
62       mCallback.releaseNetwork();
63     }
64   }
65 
66   public static class RequestFailedException extends Exception {
67 
RequestFailedException(Throwable cause)68     private RequestFailedException(Throwable cause) {
69       super(cause);
70     }
71   }
72 
73   @NonNull
getNetwork( OmtpVvmCarrierConfigHelper config, PhoneAccountHandle handle, VoicemailStatus.Editor status)74   public static NetworkWrapper getNetwork(
75       OmtpVvmCarrierConfigHelper config, PhoneAccountHandle handle, VoicemailStatus.Editor status)
76       throws RequestFailedException {
77     FutureNetworkRequestCallback callback =
78         new FutureNetworkRequestCallback(config, handle, status);
79     callback.requestNetwork();
80     try {
81       return callback.getFuture().get();
82     } catch (InterruptedException | ExecutionException e) {
83       callback.releaseNetwork();
84       VvmLog.e(TAG, "can't get future network", e);
85       throw new RequestFailedException(e);
86     }
87   }
88 
89   private static class FutureNetworkRequestCallback extends VvmNetworkRequestCallback {
90 
91     /**
92      * {@link CompletableFuture#get()} will block until {@link CompletableFuture# complete(Object) }
93      * has been called on the other thread.
94      */
95     private final CompletableFuture<NetworkWrapper> mFuture = new CompletableFuture<>();
96 
FutureNetworkRequestCallback( OmtpVvmCarrierConfigHelper config, PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status)97     public FutureNetworkRequestCallback(
98         OmtpVvmCarrierConfigHelper config,
99         PhoneAccountHandle phoneAccount,
100         VoicemailStatus.Editor status) {
101       super(config, phoneAccount, status);
102     }
103 
getFuture()104     public Future<NetworkWrapper> getFuture() {
105       return mFuture;
106     }
107 
108     @Override
onAvailable(Network network)109     public void onAvailable(Network network) {
110       super.onAvailable(network);
111       mFuture.complete(new NetworkWrapper(network, this));
112     }
113 
114     @Override
onFailed(String reason)115     public void onFailed(String reason) {
116       super.onFailed(reason);
117       mFuture.complete(null);
118     }
119   }
120 }
121