1d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian/*
2d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Copyright (C) 2016 The Android Open Source Project
3d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
4d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
5d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * you may not use this file except in compliance with the License.
6d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * You may obtain a copy of the License at
7d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
8d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
9d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian *
10d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Unless required by applicable law or agreed to in writing, software
11d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
12d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * See the License for the specific language governing permissions and
14d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * limitations under the License
15d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */
16d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
17d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianpackage com.android.voicemail.impl.sync;
18d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
19d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.annotation.TargetApi;
20d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.net.Network;
21d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.os.Build.VERSION_CODES;
22d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.support.annotation.NonNull;
23d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.telecom.PhoneAccountHandle;
24d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.voicemail.impl.OmtpVvmCarrierConfigHelper;
25d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.voicemail.impl.VoicemailStatus;
26d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.voicemail.impl.VvmLog;
27d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.io.Closeable;
28d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.concurrent.CompletableFuture;
29d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.concurrent.ExecutionException;
30d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.concurrent.Future;
31d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
32d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian/**
33d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * Class to retrieve a {@link Network} synchronously. {@link #getNetwork(OmtpVvmCarrierConfigHelper,
34d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian * PhoneAccountHandle)} will block until a suitable network is retrieved or it has failed.
35d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian */
36d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian@SuppressWarnings("AndroidApiChecker") /* CompletableFuture is java8*/
37d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian@TargetApi(VERSION_CODES.O)
38d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianpublic class VvmNetworkRequest {
39d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
40d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static final String TAG = "VvmNetworkRequest";
41d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
42d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  /**
43d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * A wrapper around a Network returned by a {@link VvmNetworkRequestCallback}, which should be
44d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   * closed once not needed anymore.
45d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian   */
46d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static class NetworkWrapper implements Closeable {
47d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
48d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    private final Network mNetwork;
49d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    private final VvmNetworkRequestCallback mCallback;
50d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
51d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    private NetworkWrapper(Network network, VvmNetworkRequestCallback callback) {
52d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      mNetwork = network;
53d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      mCallback = callback;
54d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
55d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
56d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public Network get() {
57d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      return mNetwork;
58d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
59d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
60d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    @Override
61d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public void close() {
62d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      mCallback.releaseNetwork();
63d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
64d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
65d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
66d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static class RequestFailedException extends Exception {
67d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
68d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    private RequestFailedException(Throwable cause) {
69d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      super(cause);
70d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
71d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
72d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
73d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  @NonNull
74d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  public static NetworkWrapper getNetwork(
75d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      OmtpVvmCarrierConfigHelper config, PhoneAccountHandle handle, VoicemailStatus.Editor status)
76d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      throws RequestFailedException {
77d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    FutureNetworkRequestCallback callback =
78d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        new FutureNetworkRequestCallback(config, handle, status);
79d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    callback.requestNetwork();
80d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    try {
81d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      return callback.getFuture().get();
82d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    } catch (InterruptedException | ExecutionException e) {
83d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      callback.releaseNetwork();
84d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      VvmLog.e(TAG, "can't get future network", e);
85d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      throw new RequestFailedException(e);
86d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
87d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
88d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
89d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  private static class FutureNetworkRequestCallback extends VvmNetworkRequestCallback {
90d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
91d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    /**
92d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian     * {@link CompletableFuture#get()} will block until {@link CompletableFuture# complete(Object) }
93d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian     * has been called on the other thread.
94d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian     */
95d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    private final CompletableFuture<NetworkWrapper> mFuture = new CompletableFuture<>();
96d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
97d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public FutureNetworkRequestCallback(
98d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        OmtpVvmCarrierConfigHelper config,
99d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        PhoneAccountHandle phoneAccount,
100d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian        VoicemailStatus.Editor status) {
101d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      super(config, phoneAccount, status);
102d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
103d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
104d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public Future<NetworkWrapper> getFuture() {
105d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      return mFuture;
106d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
107d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
108d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    @Override
109d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public void onAvailable(Network network) {
110d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      super.onAvailable(network);
111d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      mFuture.complete(new NetworkWrapper(network, this));
112d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
113d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian
114d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    @Override
115d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    public void onFailed(String reason) {
116d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      super.onFailed(reason);
117d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian      mFuture.complete(null);
118d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian    }
119d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian  }
120d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian}
121