Add checkMobileProvisioning to ConnectivityService.
Bug: 9279964 Change-Id: I42c326a21e05aa301e9d974ed9ac1d59472780ec
This commit is contained in:
@@ -25,6 +25,7 @@ import android.os.Binder;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.provider.Settings;
|
||||
|
||||
import java.net.InetAddress;
|
||||
@@ -1294,4 +1295,67 @@ public class ConnectivityManager {
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
|
||||
*/
|
||||
|
||||
/**
|
||||
* No connection was possible to the network.
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
|
||||
|
||||
/**
|
||||
* A connection was made to the internet, all is well.
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int CMP_RESULT_CODE_CONNECTABLE = 1;
|
||||
|
||||
/**
|
||||
* A connection was made but there was a redirection, we appear to be in walled garden.
|
||||
* This is an indication of a warm sim on a mobile network.
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int CMP_RESULT_CODE_REDIRECTED = 2;
|
||||
|
||||
/**
|
||||
* A connection was made but no dns server was available to resolve a name to address.
|
||||
* This is an indication of a warm sim on a mobile network.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int CMP_RESULT_CODE_NO_DNS = 3;
|
||||
|
||||
/**
|
||||
* A connection was made but could not open a TCP connection.
|
||||
* This is an indication of a warm sim on a mobile network.
|
||||
* {@hide}
|
||||
*/
|
||||
public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;
|
||||
|
||||
/**
|
||||
* Check mobile provisioning. The resultCode passed to
|
||||
* onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above.
|
||||
* This may take a minute or more to complete.
|
||||
*
|
||||
* @param sendNotificaiton, when true a notification will be sent to user.
|
||||
* @param suggestedTimeOutMs, timeout in milliseconds
|
||||
* @param resultReceiver needs to be supplied to receive the result
|
||||
*
|
||||
* @return time out that will be used, maybe less that suggestedTimeOutMs
|
||||
* -1 if an error.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
|
||||
ResultReceiver resultReceiver) {
|
||||
int timeOutMs = -1;
|
||||
try {
|
||||
timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
|
||||
resultReceiver);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return timeOutMs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.net.ProxyProperties;
|
||||
import android.os.IBinder;
|
||||
import android.os.Messenger;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.ResultReceiver;
|
||||
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
@@ -131,4 +132,6 @@ interface IConnectivityManager
|
||||
void supplyMessenger(int networkType, in Messenger messenger);
|
||||
|
||||
int findConnectionTypeForIface(in String iface);
|
||||
|
||||
int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.BluetoothTetheringDataTracker;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
@@ -52,11 +55,13 @@ import android.net.INetworkPolicyManager;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Uri;
|
||||
import android.net.LinkProperties.CompareResult;
|
||||
import android.net.MobileDataStateTracker;
|
||||
import android.net.NetworkConfig;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.net.NetworkQuotaInfo;
|
||||
import android.net.NetworkState;
|
||||
import android.net.NetworkStateTracker;
|
||||
@@ -66,6 +71,7 @@ import android.net.ProxyProperties;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.wifi.WifiStateTracker;
|
||||
import android.net.wimax.WimaxManagerConstants;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Binder;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
@@ -79,6 +85,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
@@ -86,13 +93,16 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.security.Credentials;
|
||||
import android.security.KeyStore;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
import com.android.internal.telephony.DctConstants;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneConstants;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
@@ -111,9 +121,11 @@ import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -121,6 +133,8 @@ import java.util.Collection;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -141,6 +155,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
|
||||
"android.telephony.apn-restore";
|
||||
|
||||
// Default value if FAIL_FAST_TIME_MS is not set
|
||||
private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000;
|
||||
// system property that can override DEFAULT_FAIL_FAST_TIME_MS
|
||||
private static final String FAIL_FAST_TIME_MS =
|
||||
"persist.radio.fail_fast_time_ms";
|
||||
|
||||
// used in recursive route setting to add gateways for the host for which
|
||||
// a host route was requested.
|
||||
private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
|
||||
@@ -292,6 +312,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
|
||||
private static final int EVENT_VPN_STATE_CHANGED = 14;
|
||||
|
||||
/**
|
||||
* Used internally to disable fail fast of mobile data
|
||||
*/
|
||||
private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15;
|
||||
|
||||
/** Handler used for internal events. */
|
||||
private InternalHandler mHandler;
|
||||
/** Handler used for incoming {@link NetworkStateTracker} events. */
|
||||
@@ -346,6 +371,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
// the set of network types that can only be enabled by system/sig apps
|
||||
List mProtectedNetworks;
|
||||
|
||||
private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
|
||||
|
||||
TelephonyManager mTelephonyManager;
|
||||
|
||||
public ConnectivityService(Context context, INetworkManagementService netd,
|
||||
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
|
||||
// Currently, omitting a NetworkFactory will create one internally
|
||||
@@ -394,6 +423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
mNetd = checkNotNull(netManager, "missing INetworkManagementService");
|
||||
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
|
||||
mKeyStore = KeyStore.getInstance();
|
||||
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
||||
try {
|
||||
mPolicyManager.registerListener(mPolicyListener);
|
||||
@@ -1408,8 +1438,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
netState != DetailedState.CAPTIVE_PORTAL_CHECK) ||
|
||||
tracker.isTeardownRequested()) {
|
||||
if (VDBG) {
|
||||
log("requestRouteToHostAddress on down network " +
|
||||
"(" + networkType + ") - dropped");
|
||||
log("requestRouteToHostAddress on down network "
|
||||
+ "(" + networkType + ") - dropped"
|
||||
+ " tracker=" + tracker
|
||||
+ " netState=" + netState
|
||||
+ " isTeardownRequested="
|
||||
+ ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1417,12 +1451,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByAddress(hostAddress);
|
||||
LinkProperties lp = tracker.getLinkProperties();
|
||||
return addRouteToAddress(lp, addr);
|
||||
boolean ok = addRouteToAddress(lp, addr);
|
||||
if (DBG) log("requestRouteToHostAddress ok=" + ok);
|
||||
return ok;
|
||||
} catch (UnknownHostException e) {
|
||||
if (DBG) log("requestRouteToHostAddress got " + e.toString());
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
if (DBG) log("requestRouteToHostAddress X bottom return false");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2824,6 +2861,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
|
||||
int tag = mEnableFailFastMobileDataTag.get();
|
||||
if (msg.arg1 == tag) {
|
||||
MobileDataStateTracker mobileDst =
|
||||
(MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE];
|
||||
if (mobileDst != null) {
|
||||
mobileDst.setEnableFailFastMobileData(msg.arg2);
|
||||
}
|
||||
} else {
|
||||
log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
|
||||
+ " != tag:" + tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3472,4 +3522,460 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
}
|
||||
return ConnectivityManager.TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have mobile data fail fast if enabled.
|
||||
*
|
||||
* @param enabled DctConstants.ENABLED/DISABLED
|
||||
*/
|
||||
private void setEnableFailFastMobileData(int enabled) {
|
||||
int tag;
|
||||
|
||||
if (enabled == DctConstants.ENABLED) {
|
||||
tag = mEnableFailFastMobileDataTag.incrementAndGet();
|
||||
} else {
|
||||
tag = mEnableFailFastMobileDataTag.get();
|
||||
}
|
||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag,
|
||||
enabled));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
|
||||
final ResultReceiver resultReceiver) {
|
||||
log("checkMobileProvisioning: E sendNotification=" + sendNotification
|
||||
+ " suggestedTimeOutMs=" + suggestedTimeOutMs
|
||||
+ " resultReceiver=" + resultReceiver);
|
||||
enforceChangePermission();
|
||||
|
||||
int timeOutMs = suggestedTimeOutMs;
|
||||
if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
|
||||
timeOutMs = CheckMp.MAX_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
CheckMp checkMp = new CheckMp(mContext, this);
|
||||
CheckMp.CallBack cb = new CheckMp.CallBack() {
|
||||
@Override
|
||||
void onComplete(Integer result) {
|
||||
log("CheckMp.onComplete: result=" + result);
|
||||
if (resultReceiver != null) {
|
||||
log("CheckMp.onComplete: send result");
|
||||
resultReceiver.send(result, null);
|
||||
}
|
||||
NetworkInfo ni =
|
||||
mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
|
||||
switch(result) {
|
||||
case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE:
|
||||
case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: {
|
||||
log("CheckMp.onComplete: ignore, connected or no connection");
|
||||
break;
|
||||
}
|
||||
case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
|
||||
log("CheckMp.onComplete: warm sim");
|
||||
String url = getProvisioningUrl();
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
url = mContext.getResources()
|
||||
.getString(R.string.mobile_redirected_provisioning_url);
|
||||
}
|
||||
if (TextUtils.isEmpty(url) == false) {
|
||||
log("CheckMp.onComplete: warm sim (redirected), url=" + url);
|
||||
setNotificationVisible(true, ni, url);
|
||||
} else {
|
||||
log("CheckMp.onComplete: warm sim (redirected), no url");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
|
||||
case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
|
||||
String url = getProvisioningUrl();
|
||||
if (TextUtils.isEmpty(url) == false) {
|
||||
log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
|
||||
setNotificationVisible(true, ni, url);
|
||||
} else {
|
||||
log("CheckMp.onComplete: warm sim (no dns/tcp), no url");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
loge("CheckMp.onComplete: ignore unexpected result=" + result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
CheckMp.Params params =
|
||||
new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
|
||||
log("checkMobileProvisioning: params=" + params);
|
||||
setNotificationVisible(false, null, null);
|
||||
checkMp.execute(params);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
log("checkMobileProvisioning: X");
|
||||
}
|
||||
return timeOutMs;
|
||||
}
|
||||
|
||||
static class CheckMp extends
|
||||
AsyncTask<CheckMp.Params, Void, Integer> {
|
||||
private static final String CHECKMP_TAG = "CheckMp";
|
||||
public static final int MAX_TIMEOUT_MS = 60000;
|
||||
private static final int SOCKET_TIMEOUT_MS = 5000;
|
||||
private Context mContext;
|
||||
private ConnectivityService mCs;
|
||||
private TelephonyManager mTm;
|
||||
private Params mParams;
|
||||
|
||||
/**
|
||||
* Parameters for AsyncTask.execute
|
||||
*/
|
||||
static class Params {
|
||||
private String mUrl;
|
||||
private long mTimeOutMs;
|
||||
private CallBack mCb;
|
||||
|
||||
Params(String url, long timeOutMs, CallBack cb) {
|
||||
mUrl = url;
|
||||
mTimeOutMs = timeOutMs;
|
||||
mCb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The call back object passed in Params. onComplete will be called
|
||||
* on the main thread.
|
||||
*/
|
||||
abstract static class CallBack {
|
||||
// Called on the main thread.
|
||||
abstract void onComplete(Integer result);
|
||||
}
|
||||
|
||||
public CheckMp(Context context, ConnectivityService cs) {
|
||||
mContext = context;
|
||||
mCs = cs;
|
||||
|
||||
// Setup access to TelephonyService we'll be using.
|
||||
mTm = (TelephonyManager) mContext.getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default url to use for the test.
|
||||
*/
|
||||
public String getDefaultUrl() {
|
||||
// See http://go/clientsdns for usage approval
|
||||
String server = Settings.Global.getString(mContext.getContentResolver(),
|
||||
Settings.Global.CAPTIVE_PORTAL_SERVER);
|
||||
if (server == null) {
|
||||
server = "clients3.google.com";
|
||||
}
|
||||
return "http://" + server + "/generate_204";
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if its possible to connect to the http url. DNS based detection techniques
|
||||
* do not work at all hotspots. The best way to check is to perform a request to
|
||||
* a known address that fetches the data we expect.
|
||||
*/
|
||||
private synchronized Integer isMobileOk(Params params) {
|
||||
Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
|
||||
Uri orgUri = Uri.parse(params.mUrl);
|
||||
Random rand = new Random();
|
||||
mParams = params;
|
||||
|
||||
try {
|
||||
if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
|
||||
log("isMobileOk: not mobile capable");
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Enable fail fast as we'll do retries here and use a
|
||||
// hipri connection so the default connection stays active.
|
||||
log("isMobileOk: start hipri url=" + params.mUrl);
|
||||
mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
|
||||
mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
|
||||
Phone.FEATURE_ENABLE_HIPRI, new Binder());
|
||||
|
||||
// Continue trying to connect until time has run out
|
||||
long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
|
||||
while(SystemClock.elapsedRealtime() < endTime) {
|
||||
try {
|
||||
// Wait for hipri to connect.
|
||||
// TODO: Don't poll and handle situation where hipri fails
|
||||
// because default is retrying. See b/9569540
|
||||
NetworkInfo.State state = mCs
|
||||
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
|
||||
if (state != NetworkInfo.State.CONNECTED) {
|
||||
log("isMobileOk: not connected ni=" +
|
||||
mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
|
||||
sleep(1);
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get of the addresses associated with the url host. We need to use the
|
||||
// address otherwise HttpURLConnection object will use the name to get
|
||||
// the addresses and is will try every address but that will bypass the
|
||||
// route to host we setup and the connection could succeed as the default
|
||||
// interface might be connected to the internet via wifi or other interface.
|
||||
InetAddress[] addresses;
|
||||
try {
|
||||
addresses = InetAddress.getAllByName(orgUri.getHost());
|
||||
} catch (UnknownHostException e) {
|
||||
log("isMobileOk: UnknownHostException");
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS;
|
||||
return result;
|
||||
}
|
||||
log("isMobileOk: addresses=" + inetAddressesToString(addresses));
|
||||
|
||||
// Get the type of addresses supported by this link
|
||||
LinkProperties lp = mCs.getLinkProperties(
|
||||
ConnectivityManager.TYPE_MOBILE_HIPRI);
|
||||
boolean linkHasIpv4 = hasIPv4Address(lp);
|
||||
boolean linkHasIpv6 = hasIPv6Address(lp);
|
||||
log("isMobileOk: linkHasIpv4=" + linkHasIpv4
|
||||
+ " linkHasIpv6=" + linkHasIpv6);
|
||||
|
||||
// Loop through at most 3 valid addresses or all of the address or until
|
||||
// we run out of time
|
||||
int loops = Math.min(3, addresses.length);
|
||||
for(int validAddr=0, addrTried=0;
|
||||
(validAddr < loops) && (addrTried < addresses.length)
|
||||
&& (SystemClock.elapsedRealtime() < endTime);
|
||||
addrTried ++) {
|
||||
|
||||
// Choose the address at random but make sure its type is supported
|
||||
InetAddress hostAddr = addresses[rand.nextInt(addresses.length)];
|
||||
if (((hostAddr instanceof Inet4Address) && linkHasIpv4)
|
||||
|| ((hostAddr instanceof Inet6Address) && linkHasIpv6)) {
|
||||
// Valid address, so use it
|
||||
validAddr += 1;
|
||||
} else {
|
||||
// Invalid address so try next address
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make a route to host so we check the specific interface.
|
||||
if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
|
||||
hostAddr.getAddress())) {
|
||||
// Wait a short time to be sure the route is established ??
|
||||
log("isMobileOk:"
|
||||
+ " wait to establish route to hostAddr=" + hostAddr);
|
||||
sleep(3);
|
||||
} else {
|
||||
log("isMobileOk:"
|
||||
+ " could not establish route to hostAddr=" + hostAddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rewrite the url to have numeric address to use the specific route.
|
||||
// I also set the "Connection" to "Close" as by default "Keep-Alive"
|
||||
// is used which is useless in this case.
|
||||
URL newUrl = new URL(orgUri.getScheme() + "://"
|
||||
+ hostAddr.getHostAddress() + orgUri.getPath());
|
||||
log("isMobileOk: newUrl=" + newUrl);
|
||||
|
||||
HttpURLConnection urlConn = null;
|
||||
try {
|
||||
// Open the connection set the request header and get the response
|
||||
urlConn = (HttpURLConnection) newUrl.openConnection(
|
||||
java.net.Proxy.NO_PROXY);
|
||||
urlConn.setInstanceFollowRedirects(false);
|
||||
urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
|
||||
urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
|
||||
urlConn.setUseCaches(false);
|
||||
urlConn.setAllowUserInteraction(false);
|
||||
urlConn.setRequestProperty("Connection", "close");
|
||||
int responseCode = urlConn.getResponseCode();
|
||||
if (responseCode == 204) {
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE;
|
||||
} else {
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED;
|
||||
}
|
||||
log("isMobileOk: connected responseCode=" + responseCode);
|
||||
urlConn.disconnect();
|
||||
urlConn = null;
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log("isMobileOk: HttpURLConnection Exception e=" + e);
|
||||
if (urlConn != null) {
|
||||
urlConn.disconnect();
|
||||
urlConn = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION;
|
||||
log("isMobileOk: loops|timed out");
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log("isMobileOk: Exception e=" + e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
log("isMobileOk: timed out");
|
||||
} finally {
|
||||
log("isMobileOk: F stop hipri");
|
||||
mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
|
||||
mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
|
||||
Phone.FEATURE_ENABLE_HIPRI);
|
||||
log("isMobileOk: X result=" + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Params... params) {
|
||||
return isMobileOk(params[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
log("onPostExecute: result=" + result);
|
||||
if ((mParams != null) && (mParams.mCb != null)) {
|
||||
mParams.mCb.onComplete(result);
|
||||
}
|
||||
}
|
||||
|
||||
private String inetAddressesToString(InetAddress[] addresses) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
boolean firstTime = true;
|
||||
for(InetAddress addr : addresses) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
} else {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(addr);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void printNetworkInfo() {
|
||||
boolean hasIccCard = mTm.hasIccCard();
|
||||
int simState = mTm.getSimState();
|
||||
log("hasIccCard=" + hasIccCard
|
||||
+ " simState=" + simState);
|
||||
NetworkInfo[] ni = mCs.getAllNetworkInfo();
|
||||
if (ni != null) {
|
||||
log("ni.length=" + ni.length);
|
||||
for (NetworkInfo netInfo: ni) {
|
||||
log("netInfo=" + netInfo.toString());
|
||||
}
|
||||
} else {
|
||||
log("no network info ni=null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for a few seconds then return.
|
||||
* @param seconds
|
||||
*/
|
||||
private static void sleep(int seconds) {
|
||||
try {
|
||||
Thread.sleep(seconds * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasIPv4Address(LinkProperties lp) {
|
||||
return lp.hasIPv4Address();
|
||||
}
|
||||
|
||||
// Not implemented in LinkProperties, do it here.
|
||||
public boolean hasIPv6Address(LinkProperties lp) {
|
||||
for (LinkAddress address : lp.getLinkAddresses()) {
|
||||
if (address.getAddress() instanceof Inet6Address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void log(String s) {
|
||||
Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
|
||||
|
||||
private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) {
|
||||
log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url);
|
||||
|
||||
Resources r = Resources.getSystem();
|
||||
NotificationManager notificationManager = (NotificationManager) mContext
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (visible) {
|
||||
CharSequence title;
|
||||
CharSequence details;
|
||||
int icon;
|
||||
switch (networkInfo.getType()) {
|
||||
case ConnectivityManager.TYPE_WIFI:
|
||||
log("setNotificationVisible: TYPE_WIFI");
|
||||
title = r.getString(R.string.wifi_available_sign_in, 0);
|
||||
details = r.getString(R.string.network_available_sign_in_detailed,
|
||||
networkInfo.getExtraInfo());
|
||||
icon = R.drawable.stat_notify_wifi_in_range;
|
||||
break;
|
||||
case ConnectivityManager.TYPE_MOBILE:
|
||||
case ConnectivityManager.TYPE_MOBILE_HIPRI:
|
||||
log("setNotificationVisible: TYPE_MOBILE|HIPRI");
|
||||
title = r.getString(R.string.network_available_sign_in, 0);
|
||||
// TODO: Change this to pull from NetworkInfo once a printable
|
||||
// name has been added to it
|
||||
details = mTelephonyManager.getNetworkOperatorName();
|
||||
icon = R.drawable.stat_notify_rssi_in_range;
|
||||
break;
|
||||
default:
|
||||
log("setNotificationVisible: other type=" + networkInfo.getType());
|
||||
title = r.getString(R.string.network_available_sign_in, 0);
|
||||
details = r.getString(R.string.network_available_sign_in_detailed,
|
||||
networkInfo.getExtraInfo());
|
||||
icon = R.drawable.stat_notify_rssi_in_range;
|
||||
break;
|
||||
}
|
||||
|
||||
Notification notification = new Notification();
|
||||
notification.when = 0;
|
||||
notification.icon = icon;
|
||||
notification.flags = Notification.FLAG_AUTO_CANCEL;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
|
||||
notification.tickerText = title;
|
||||
notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
|
||||
|
||||
log("setNotificaitionVisible: notify notificaiton=" + notification);
|
||||
notificationManager.notify(NOTIFICATION_ID, 1, notification);
|
||||
} else {
|
||||
log("setNotificaitionVisible: cancel");
|
||||
notificationManager.cancel(NOTIFICATION_ID, 1);
|
||||
}
|
||||
log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
|
||||
}
|
||||
|
||||
private String getProvisioningUrl() {
|
||||
String url = mContext.getResources().getString(R.string.mobile_provisioning_url);
|
||||
log("getProvisioningUrl: resource url=" + url);
|
||||
|
||||
// populate the iccid and imei in the provisioning url.
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
url = String.format(url,
|
||||
mTelephonyManager.getSimSerialNumber() /* ICCID */,
|
||||
mTelephonyManager.getDeviceId() /* IMEI */,
|
||||
mTelephonyManager.getLine1Number() /* Phone numer */);
|
||||
}
|
||||
|
||||
log("getProvisioningUrl: url=" + url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user