1 /* 2 * Copyright (C) 2015 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 package com.android.phone.vvm.omtp.sync; 17 18 import android.annotation.CallSuper; 19 import android.content.Context; 20 import android.net.ConnectivityManager; 21 import android.net.Network; 22 import android.net.NetworkCapabilities; 23 import android.net.NetworkRequest; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.provider.VoicemailContract; 27 import android.provider.VoicemailContract.Status; 28 import android.telecom.PhoneAccountHandle; 29 import android.util.Log; 30 31 import com.android.phone.PhoneUtils; 32 import com.android.phone.VoicemailUtils; 33 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper; 34 35 /** 36 * Base class for network request call backs for visual voicemail syncing with the Imap server. This 37 * handles retries and network requests. 38 */ 39 public abstract class VvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback { 40 41 private static final String TAG = "VvmNetworkRequest"; 42 43 // Timeout used to call ConnectivityManager.requestNetwork 44 private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000; 45 46 public static final String NETWORK_REQUEST_FAILED_TIMEOUT = "timeout"; 47 public static final String NETWORK_REQUEST_FAILED_LOST = "lost"; 48 49 protected Context mContext; 50 protected PhoneAccountHandle mPhoneAccount; 51 protected NetworkRequest mNetworkRequest; 52 private ConnectivityManager mConnectivityManager; 53 private final OmtpVvmCarrierConfigHelper mCarrierConfigHelper; 54 private final int mSubId; 55 private boolean mRequestSent = false; 56 private boolean mResultReceived = false; 57 58 public VvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount) { 59 mContext = context; 60 mPhoneAccount = phoneAccount; 61 mSubId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount); 62 mCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(context, mSubId); 63 mNetworkRequest = createNetworkRequest(); 64 } 65 66 /** 67 * @return NetworkRequest for a proper transport type. Use only cellular network if the carrier 68 * requires it. Otherwise use whatever available. 69 */ 70 private NetworkRequest createNetworkRequest() { 71 72 NetworkRequest.Builder builder = new NetworkRequest.Builder() 73 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 74 75 if (mCarrierConfigHelper.isCellularDataRequired()) { 76 Log.d(TAG, "Transport type: CELLULAR"); 77 builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 78 .setNetworkSpecifier(Integer.toString(mSubId)); 79 } else { 80 Log.d(TAG, "Transport type: ANY"); 81 } 82 return builder.build(); 83 } 84 85 public NetworkRequest getNetworkRequest() { 86 return mNetworkRequest; 87 } 88 89 @Override 90 @CallSuper 91 public void onLost(Network network) { 92 Log.d(TAG, "onLost"); 93 mResultReceived = true; 94 onFailed(NETWORK_REQUEST_FAILED_LOST); 95 } 96 97 @Override 98 @CallSuper 99 public void onAvailable(Network network) { 100 super.onAvailable(network); 101 mResultReceived = true; 102 } 103 104 @Override 105 @CallSuper 106 public void onUnavailable() { 107 mResultReceived = true; 108 onFailed(NETWORK_REQUEST_FAILED_TIMEOUT); 109 } 110 111 public void requestNetwork() { 112 if (mRequestSent == true) { 113 Log.e(TAG, "requestNetwork() called twice"); 114 return; 115 } 116 mRequestSent = true; 117 getConnectivityManager().requestNetwork(getNetworkRequest(), this); 118 /** 119 * Somehow requestNetwork() with timeout doesn't work, and it's a hidden method. 120 * Implement our own timeout mechanism instead. 121 */ 122 Handler handler = new Handler(Looper.getMainLooper()); 123 handler.postDelayed(new Runnable() { 124 @Override 125 public void run() { 126 if (mResultReceived == false) { 127 onFailed(NETWORK_REQUEST_FAILED_TIMEOUT); 128 } 129 } 130 }, NETWORK_REQUEST_TIMEOUT_MILLIS); 131 } 132 133 public void releaseNetwork() { 134 Log.d(TAG, "releaseNetwork"); 135 getConnectivityManager().unregisterNetworkCallback(this); 136 } 137 138 public ConnectivityManager getConnectivityManager() { 139 if (mConnectivityManager == null) { 140 mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 141 Context.CONNECTIVITY_SERVICE); 142 } 143 return mConnectivityManager; 144 } 145 146 @CallSuper 147 public void onFailed(String reason) { 148 Log.d(TAG, "onFailed: " + reason); 149 if (mCarrierConfigHelper.isCellularDataRequired()) { 150 VoicemailUtils.setDataChannelState( 151 mContext, mPhoneAccount, 152 Status.DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED); 153 } else { 154 VoicemailUtils.setDataChannelState( 155 mContext, mPhoneAccount, Status.DATA_CHANNEL_STATE_NO_CONNECTION); 156 } 157 releaseNetwork(); 158 } 159 } 160