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