Merge "Telephony: SMS over IMS, DO NOT MERGE" into jb-mr2-dev
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 81c0a6a..0aedecb 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -152,6 +152,11 @@
// not implemented
}
+ @Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ // not implemented
+ }
+
/**
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 1165281..e87f84c 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -102,6 +102,11 @@
}
@Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ // not implemented
+ }
+
+ @Override
public boolean setRadio(boolean turnOn) {
// Base tracker doesn't handle radios
return true;
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 21995c0..19c5f39 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -34,6 +34,7 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -42,6 +43,7 @@
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Inet4Address;
+import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
@@ -52,17 +54,15 @@
* @hide
*/
public class CaptivePortalTracker extends StateMachine {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String TAG = "CaptivePortalTracker";
private static final String DEFAULT_SERVER = "clients3.google.com";
- private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
private static final int SOCKET_TIMEOUT_MS = 10000;
private String mServer;
private String mUrl;
- private boolean mNotificationShown = false;
private boolean mIsCaptivePortalCheckEnabled = false;
private IConnectivityManager mConnService;
private TelephonyManager mTelephonyManager;
@@ -159,12 +159,12 @@
private class DefaultState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
+ setNotificationOff();
}
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
switch (message.what) {
case CMD_DETECT_PORTAL:
NetworkInfo info = (NetworkInfo) message.obj;
@@ -186,23 +186,24 @@
private class NoActiveNetworkState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
mNetworkInfo = null;
- /* Clear any previous notification */
- setNotificationVisible(false);
}
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
InetAddress server;
NetworkInfo info;
switch (message.what) {
case CMD_CONNECTIVITY_CHANGE:
info = (NetworkInfo) message.obj;
- if (info.isConnected() && isActiveNetwork(info)) {
- mNetworkInfo = info;
- transitionTo(mDelayedCaptiveCheckState);
+ if (info.getType() == ConnectivityManager.TYPE_WIFI) {
+ if (info.isConnected() && isActiveNetwork(info)) {
+ mNetworkInfo = info;
+ transitionTo(mDelayedCaptiveCheckState);
+ }
+ } else {
+ log(getName() + " not a wifi connectivity change, ignore");
}
break;
default:
@@ -215,7 +216,7 @@
private class ActiveNetworkState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
+ setNotificationOff();
}
@Override
@@ -248,7 +249,6 @@
private class DelayedCaptiveCheckState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
if (mDeviceProvisioned) {
sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
@@ -259,7 +259,7 @@
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
switch (message.what) {
case CMD_DELAYED_CAPTIVE_CHECK:
if (message.arg1 == mDelayedCheckToken) {
@@ -270,11 +270,17 @@
} else {
if (DBG) log("Not captive network " + mNetworkInfo);
}
+ notifyPortalCheckCompleted(mNetworkInfo, captive);
if (mDeviceProvisioned) {
if (captive) {
// Setup Wizard will assist the user in connecting to a captive
// portal, so make the notification visible unless during setup
- setNotificationVisible(true);
+ try {
+ mConnService.setProvisioningNotificationVisible(true,
+ mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl);
+ } catch(RemoteException e) {
+ e.printStackTrace();
+ }
}
} else {
Intent intent = new Intent(
@@ -300,12 +306,26 @@
return;
}
try {
+ if (DBG) log("notifyPortalCheckComplete: ni=" + info);
mConnService.captivePortalCheckComplete(info);
} catch(RemoteException e) {
e.printStackTrace();
}
}
+ private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+ if (info == null) {
+ loge("notifyPortalCheckComplete on null");
+ return;
+ }
+ try {
+ if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info);
+ mConnService.captivePortalCheckCompleted(info, isCaptivePortal);
+ } catch(RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
private boolean isActiveNetwork(NetworkInfo info) {
try {
NetworkInfo active = mConnService.getActiveNetworkInfo();
@@ -318,6 +338,15 @@
return false;
}
+ private void setNotificationOff() {
+ try {
+ mConnService.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_NONE,
+ null, null);
+ } catch (RemoteException e) {
+ log("setNotificationOff: " + e);
+ }
+ }
+
/**
* Do a URL fetch on a known server to see if we get the data we expect
*/
@@ -360,58 +389,4 @@
}
return null;
}
-
- private void setNotificationVisible(boolean visible) {
- // if it should be hidden and it is already hidden, then noop
- if (!visible && !mNotificationShown) {
- return;
- }
-
- Resources r = Resources.getSystem();
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- if (visible) {
- CharSequence title;
- CharSequence details;
- int icon;
- switch (mNetworkInfo.getType()) {
- case ConnectivityManager.TYPE_WIFI:
- title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- mNetworkInfo.getExtraInfo());
- icon = R.drawable.stat_notify_wifi_in_range;
- break;
- case ConnectivityManager.TYPE_MOBILE:
- 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:
- title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- mNetworkInfo.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(mUrl));
- 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);
-
- notificationManager.notify(NOTIFICATION_ID, 1, notification);
- } else {
- notificationManager.cancel(NOTIFICATION_ID, 1);
- }
- mNotificationShown = visible;
- }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 697bde9..02a6494 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -583,6 +583,29 @@
}
/**
+ * Returns details about the Provisioning or currently active default data network. When
+ * connected, this network is the default route for outgoing connections.
+ * You should always check {@link NetworkInfo#isConnected()} before initiating
+ * network traffic. This may return {@code null} when there is no default
+ * network.
+ *
+ * @return a {@link NetworkInfo} object for the current default network
+ * or {@code null} if no network default network is currently active
+ *
+ * <p>This method requires the call to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * {@hide}
+ */
+ public NetworkInfo getProvisioningOrActiveNetworkInfo() {
+ try {
+ return mService.getProvisioningOrActiveNetworkInfo();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns the IP information for the current default network.
*
* @return a {@link LinkProperties} object describing the IP info
@@ -1283,6 +1306,25 @@
}
/**
+ * Signal that the captive portal check on the indicated network
+ * is complete and whether its a captive portal or not.
+ *
+ * @param info the {@link NetworkInfo} object for the networkType
+ * in question.
+ * @param isCaptivePortal true/false.
+ *
+ * <p>This method requires the call to hold the permission
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
+ * {@hide}
+ */
+ public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+ try {
+ mService.captivePortalCheckCompleted(info, isCaptivePortal);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Supply the backend messenger for a network tracker
*
* @param type NetworkType to set
@@ -1297,70 +1339,26 @@
}
/**
- * 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.
+ * Check mobile provisioning.
*
- * {@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) {
+ public int checkMobileProvisioning(int suggestedTimeOutMs) {
int timeOutMs = -1;
try {
- timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
- resultReceiver);
+ timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
} catch (RemoteException e) {
}
return timeOutMs;
}
/**
- * Get the carrier provisioning url.
+ * Get the mobile provisioning url.
* {@hide}
*/
public String getMobileProvisioningUrl() {
@@ -1370,4 +1368,32 @@
}
return null;
}
+
+ /**
+ * Get the mobile redirected provisioning url.
+ * {@hide}
+ */
+ public String getMobileRedirectedProvisioningUrl() {
+ try {
+ return mService.getMobileRedirectedProvisioningUrl();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Set sign in error notification to visible or in visible
+ *
+ * @param visible
+ * @param networkType
+ *
+ * {@hide}
+ */
+ public void setProvisioningNotificationVisible(boolean visible, int networkType,
+ String extraInfo, String url) {
+ try {
+ mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index 15a81f3..ee738fd 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -120,10 +120,16 @@
return true;
}
+ @Override
public void captivePortalCheckComplete() {
// not implemented
}
+ @Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ // not implemented
+ }
+
/**
* Record the detailed state of a network, and if it is a
* change from the previous state, send a notification to
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 27d5a58..ac2b0d9 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -279,6 +279,11 @@
// not implemented
}
+ @Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ // not implemented
+ }
+
/**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4600c1a..a17b4f5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -46,6 +46,8 @@
NetworkInfo getNetworkInfo(int networkType);
NetworkInfo[] getAllNetworkInfo();
+ NetworkInfo getProvisioningOrActiveNetworkInfo();
+
boolean isNetworkSupported(int networkType);
LinkProperties getActiveLinkProperties();
@@ -129,11 +131,17 @@
void captivePortalCheckComplete(in NetworkInfo info);
+ void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal);
+
void supplyMessenger(int networkType, in Messenger messenger);
int findConnectionTypeForIface(in String iface);
- int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
+ int checkMobileProvisioning(int suggestedTimeOutMs);
String getMobileProvisioningUrl();
+
+ String getMobileRedirectedProvisioningUrl();
+
+ void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 5a1daed..77b7314 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -40,6 +40,7 @@
import java.io.CharArrayWriter;
import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Track the state of mobile data connectivity. This is done by
@@ -51,7 +52,7 @@
public class MobileDataStateTracker implements NetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final boolean VDBG = false;
private PhoneConstants.DataState mMobileDataState;
@@ -75,6 +76,8 @@
private Handler mHandler;
private AsyncChannel mDataConnectionTrackerAc;
+ private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false);
+
/**
* Create a new MobileDataStateTracker
* @param netType the ConnectivityManager network type
@@ -101,6 +104,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
mContext.registerReceiver(new MobileDataStateReceiver(), filter);
@@ -168,20 +172,49 @@
public void releaseWakeLock() {
}
+ private void updateLinkProperitesAndCapatilities(Intent intent) {
+ mLinkProperties = intent.getParcelableExtra(
+ PhoneConstants.DATA_LINK_PROPERTIES_KEY);
+ if (mLinkProperties == null) {
+ loge("CONNECTED event did not supply link properties.");
+ mLinkProperties = new LinkProperties();
+ }
+ mLinkCapabilities = intent.getParcelableExtra(
+ PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
+ if (mLinkCapabilities == null) {
+ loge("CONNECTED event did not supply link capabilities.");
+ mLinkCapabilities = new LinkCapabilities();
+ }
+ }
+
private class MobileDataStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(TelephonyIntents.
+ ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
+ String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
+ String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
+ if (!TextUtils.equals(mApnType, apnType)) {
+ return;
+ }
+ if (DBG) {
+ log("Broadcast received: " + intent.getAction() + " apnType=" + apnType
+ + " apnName=" + apnName);
+ }
+
+ // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
+ mMobileDataState = PhoneConstants.DataState.CONNECTING;
+ updateLinkProperitesAndCapatilities(intent);
+ setDetailedState(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, "", apnName);
+ } else if (intent.getAction().equals(TelephonyIntents.
ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
- if (VDBG) {
- log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"
- + "mApnType=%s %s received apnType=%s", mApnType,
- TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType));
- }
if (!TextUtils.equals(apnType, mApnType)) {
return;
}
+ if (DBG) {
+ log("Broadcast received: " + intent.getAction() + " apnType=" + apnType);
+ }
int oldSubtype = mNetworkInfo.getSubtype();
int newSubType = TelephonyManager.getDefault().getNetworkType();
@@ -199,7 +232,7 @@
String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
mNetworkInfo.setRoaming(intent.getBooleanExtra(
PhoneConstants.DATA_NETWORK_ROAMING_KEY, false));
- if (VDBG) {
+ if (DBG) {
log(mApnType + " setting isAvailable to " +
intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false));
}
@@ -233,18 +266,7 @@
setDetailedState(DetailedState.SUSPENDED, reason, apnName);
break;
case CONNECTED:
- mLinkProperties = intent.getParcelableExtra(
- PhoneConstants.DATA_LINK_PROPERTIES_KEY);
- if (mLinkProperties == null) {
- loge("CONNECTED event did not supply link properties.");
- mLinkProperties = new LinkProperties();
- }
- mLinkCapabilities = intent.getParcelableExtra(
- PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
- if (mLinkCapabilities == null) {
- loge("CONNECTED event did not supply link capabilities.");
- mLinkCapabilities = new LinkCapabilities();
- }
+ updateLinkProperitesAndCapatilities(intent);
setDetailedState(DetailedState.CONNECTED, reason, apnName);
break;
}
@@ -269,18 +291,13 @@
equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
if (!TextUtils.equals(apnType, mApnType)) {
- if (DBG) {
- log(String.format(
- "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " +
- "mApnType=%s != received apnType=%s", mApnType, apnType));
- }
return;
}
String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
if (DBG) {
- log("Received " + intent.getAction() +
- " broadcast" + reason == null ? "" : "(" + reason + ")");
+ log("Broadcast received: " + intent.getAction() +
+ " reason=" + reason == null ? "null" : reason);
}
setDetailedState(DetailedState.FAILED, reason, apnName);
} else {
@@ -372,11 +389,27 @@
return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
}
+ /**
+ * @return true if this is ready to operate
+ */
+ public boolean isReady() {
+ return mDataConnectionTrackerAc != null;
+ }
+
@Override
public void captivePortalCheckComplete() {
// not implemented
}
+ @Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) {
+ // Captive portal change enable/disable failing fast
+ setEnableFailFastMobileData(
+ isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED);
+ }
+ }
+
/**
* Record the detailed state of a network, and if it is a
* change from the previous state, send a notification to
@@ -525,6 +558,40 @@
}
}
+ /**
+ * Inform DCT mobile provisioning has started, it ends when provisioning completes.
+ */
+ public void enableMobileProvisioning(String url) {
+ if (DBG) log("enableMobileProvisioning(url=" + url + ")");
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ Message msg = Message.obtain();
+ msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
+ msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
+ channel.sendMessage(msg);
+ }
+ }
+
+ /**
+ * Return if this network is the provisioning network. Valid only if connected.
+ * @param met
+ */
+ public boolean isProvisioningNetwork() {
+ boolean retVal;
+ try {
+ Message msg = Message.obtain();
+ msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
+ msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
+ Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
+ retVal = result.arg1 == DctConstants.ENABLED;
+ } catch (NullPointerException e) {
+ loge("isProvisioningNetwork: X " + e);
+ retVal = false;
+ }
+ if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
+ return retVal;
+ }
+
@Override
public void addStackedLink(LinkProperties link) {
mLinkProperties.addStackedLink(link);
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 689dae5..dabc73a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -84,6 +84,12 @@
VERIFYING_POOR_LINK,
/** Checking if network is a captive portal */
CAPTIVE_PORTAL_CHECK,
+ /**
+ * Network is connected to provisioning network
+ * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK
+ * @hide
+ */
+ CONNECTED_TO_PROVISIONING_NETWORK
}
/**
@@ -108,6 +114,7 @@
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
+ stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED);
}
private int mNetworkType;
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index cf77a1c..9ed7533 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -144,6 +144,11 @@
public void captivePortalCheckComplete();
/**
+ * Captive portal check has completed
+ */
+ public void captivePortalCheckCompleted(boolean isCaptive);
+
+ /**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}
*/
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 2a2f7cf..0fe5cc4 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -81,9 +81,6 @@
}
};
- private static final HostnameVerifier HOSTNAME_VERIFIER =
- HttpsURLConnection.getDefaultHostnameVerifier();
-
private SSLSocketFactory mInsecureFactory = null;
private SSLSocketFactory mSecureFactory = null;
private TrustManager[] mTrustManagers = null;
@@ -195,7 +192,7 @@
if (session == null) {
throw new SSLException("Cannot verify SSL socket without session");
}
- if (!HOSTNAME_VERIFIER.verify(hostname, session)) {
+ if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {
throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4bff536..c23012a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -151,6 +151,7 @@
<protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
<protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
<protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+ <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
@@ -181,6 +182,9 @@
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
+ <protected-broadcast
+ android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4572f5b..707590b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -772,6 +772,10 @@
<!-- IP address of the dns server to use if nobody else suggests one -->
<string name="config_default_dns_server" translatable="false">8.8.8.8</string>
+ <!-- The default mobile provisioning apn. Empty by default, maybe overridden by
+ an mcc/mnc specific config.xml -->
+ <string name="mobile_provisioning_apn" translatable="false"></string>
+
<!-- The default mobile provisioning url. Empty by default, maybe overridden by
an mcc/mnc specific config.xml -->
<string name="mobile_provisioning_url" translatable="false"></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b885d56..a67c2af 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -703,6 +703,7 @@
<java-symbol type="string" name="preposition_for_time" />
<java-symbol type="string" name="progress_erasing" />
<java-symbol type="string" name="progress_unmounting" />
+ <java-symbol type="string" name="mobile_provisioning_apn" />
<java-symbol type="string" name="mobile_provisioning_url" />
<java-symbol type="string" name="mobile_redirected_provisioning_url" />
<java-symbol type="string" name="reboot_safemode_confirm" />
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index f3a91c5..ee867ff 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -157,4 +157,11 @@
public static final int STREAM_H264_480_360_1411k_DURATION = 46000;
public static final int VIDEO_H263_AAC_DURATION = 501000;
public static final int VIDEO_H263_AMR_DURATION = 502000;
+
+ // Video files for WiFi IOT video streaming test.
+ public static final String[] NETWORK_VIDEO_FILES = {
+ "H264_BP_720x480_25fps_256kbps_AMRNB_8khz_12.2kbps_m_0_26.mp4",
+ "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4",
+ "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4"
+ };
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index 67da6ac..e289812 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -17,18 +17,13 @@
package com.android.mediaframeworktest.stress;
import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaPlayerStressTestRunner;
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Intent;
-import android.hardware.Camera;
-import android.media.MediaPlayer;
-import android.media.MediaRecorder;
+import android.os.Bundle;
import android.os.Environment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import android.view.SurfaceHolder;
import com.android.mediaframeworktest.MediaNames;
import com.android.mediaframeworktest.functional.CodecTest;
@@ -38,14 +33,12 @@
import java.io.FileWriter;
import java.io.Writer;
-import android.test.AndroidTestCase;
-import android.test.InstrumentationTestCase;
-
/**
* Junit / Instrumentation test case for the media player
*/
public class MediaPlayerStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
private String TAG = "MediaPlayerStressTest";
+ private String mMediaSrc;
public MediaPlayerStressTest() {
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -56,6 +49,12 @@
//the workaround for the race condition of requesting the updated surface.
Thread.sleep(2000);
getActivity();
+ MediaPlayerStressTestRunner mRunner = (MediaPlayerStressTestRunner)getInstrumentation();
+ Bundle arguments = mRunner.getArguments();
+ mMediaSrc = arguments.getString("media-source");
+ if (mMediaSrc == null) {
+ mMediaSrc = MediaNames.MEDIA_SAMPLE_POOL;
+ }
super.setUp();
}
@@ -119,17 +118,20 @@
boolean testResult = true;
// load directory files
boolean onCompleteSuccess = false;
- File dir = new File(MediaNames.MEDIA_SAMPLE_POOL);
- String[] children = dir.list();
+ String[] children = MediaNames.NETWORK_VIDEO_FILES;
+ if (MediaNames.MEDIA_SAMPLE_POOL.equals(mMediaSrc)) {
+ File dir = new File(mMediaSrc);
+ children = dir.list();
+ }
if (children == null) {
Log.v("MediaPlayerApiTest:testMediaSamples", "dir is empty");
return;
} else {
for (int i = 0; i < children.length; i++) {
- //Get filename of directory
+ //Get filename
String filename = children[i];
onCompleteSuccess =
- CodecTest.playMediaSamples(dir + "/" + filename);
+ CodecTest.playMediaSamples(mMediaSrc + filename);
if (!onCompleteSuccess){
//Don't fail the test right away, print out the failure file.
fileWithError += filename + '\n';
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 20ad636..a55fddc 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -380,12 +380,14 @@
HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
synchronized (this) {
boolean changed = false;
- for (int i=0; i<mUidOps.size(); i++) {
+ for (int i=mUidOps.size()-1; i>=0; i--) {
HashMap<String, Ops> packages = mUidOps.valueAt(i);
- for (Map.Entry<String, Ops> ent : packages.entrySet()) {
+ Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Ops> ent = it.next();
String packageName = ent.getKey();
Ops pkgOps = ent.getValue();
- for (int j=0; j<pkgOps.size(); j++) {
+ for (int j=pkgOps.size()-1; j>=0; j--) {
Op curOp = pkgOps.valueAt(j);
if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
curOp.mode = AppOpsManager.MODE_ALLOWED;
@@ -394,9 +396,17 @@
mOpModeWatchers.get(curOp.op));
callbacks = addCallbacks(callbacks, packageName, curOp.op,
mPackageModeWatchers.get(packageName));
- pruneOp(curOp, mUidOps.keyAt(i), packageName);
+ if (curOp.time == 0 && curOp.rejectTime == 0) {
+ pkgOps.removeAt(j);
+ }
}
}
+ if (pkgOps.size() == 0) {
+ it.remove();
+ }
+ }
+ if (packages.size() == 0) {
+ mUidOps.removeAt(i);
}
}
if (changed) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cb4e89c..ee23b13 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothTetheringDataTracker;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -143,6 +144,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -383,9 +385,6 @@
TelephonyManager mTelephonyManager;
- // We only want one checkMobileProvisioning after booting.
- volatile boolean mFirstProvisioningCheckStarted = false;
-
public ConnectivityService(Context context, INetworkManagementService netd,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
// Currently, omitting a NetworkFactory will create one internally
@@ -609,8 +608,9 @@
mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
mSettingsObserver.observe(mContext);
- mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
- loadGlobalProxy();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
+ mContext.registerReceiver(mProvisioningReceiver, filter);
}
/**
@@ -879,6 +879,46 @@
return getNetworkInfo(mActiveDefaultNetwork, uid);
}
+ /**
+ * Find the first Provisioning network.
+ *
+ * @return NetworkInfo or null if none.
+ */
+ private NetworkInfo getProvisioningNetworkInfo() {
+ enforceAccessPermission();
+
+ // Find the first Provisioning Network
+ NetworkInfo provNi = null;
+ for (NetworkInfo ni : getAllNetworkInfo()) {
+ if (ni.getDetailedState()
+ == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) {
+ provNi = ni;
+ break;
+ }
+ }
+ if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi);
+ return provNi;
+ }
+
+ /**
+ * Find the first Provisioning network or the ActiveDefaultNetwork
+ * if there is no Provisioning network
+ *
+ * @return NetworkInfo or null if none.
+ */
+ @Override
+ public NetworkInfo getProvisioningOrActiveNetworkInfo() {
+ enforceAccessPermission();
+
+ NetworkInfo provNi = getProvisioningNetworkInfo();
+ if (provNi == null) {
+ final int uid = Binder.getCallingUid();
+ provNi = getNetworkInfo(mActiveDefaultNetwork, uid);
+ }
+ if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi);
+ return provNi;
+ }
+
public NetworkInfo getActiveNetworkInfoUnfiltered() {
enforceAccessPermission();
if (isNetworkTypeValid(mActiveDefaultNetwork)) {
@@ -1241,8 +1281,10 @@
feature);
}
if (network.reconnect()) {
+ if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED");
return PhoneConstants.APN_REQUEST_STARTED;
} else {
+ if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED");
return PhoneConstants.APN_REQUEST_FAILED;
}
} else {
@@ -1254,9 +1296,11 @@
mNetRequestersPids[usedNetworkType].add(currentPid);
}
}
+ if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature.");
return -1;
}
}
+ if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE");
return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
} finally {
if (DBG) {
@@ -1290,11 +1334,12 @@
}
}
if (found && u != null) {
+ if (VDBG) log("stopUsingNetworkFeature: X");
// stop regardless of how many other time this proc had called start
return stopUsingNetworkFeature(u, true);
} else {
// none found!
- if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
+ if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring");
return 1;
}
}
@@ -1849,6 +1894,9 @@
*/
if (mNetConfigs[prevNetType].isDefault()) {
if (mActiveDefaultNetwork == prevNetType) {
+ if (DBG) {
+ log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
+ }
mActiveDefaultNetwork = -1;
}
@@ -2041,6 +2089,9 @@
}
void systemReady() {
+ mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
+ loadGlobalProxy();
+
synchronized(this) {
mSystemReady = true;
if (mInitialBroadcast != null) {
@@ -2071,10 +2122,11 @@
};
private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
- if ((type != mNetworkPreference &&
- mNetConfigs[mActiveDefaultNetwork].priority >
- mNetConfigs[type].priority) ||
- mNetworkPreference == mActiveDefaultNetwork) return false;
+ if (((type != mNetworkPreference)
+ && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority))
+ || (mNetworkPreference == mActiveDefaultNetwork)) {
+ return false;
+ }
return true;
}
@@ -2088,6 +2140,11 @@
final NetworkStateTracker thisNet = mNetTrackers[newNetType];
final String thisIface = thisNet.getLinkProperties().getInterfaceName();
+ if (VDBG) {
+ log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface
+ + " isFailover" + isFailover);
+ }
+
// if this is a default net and other default is running
// kill the one not preferred
if (mNetConfigs[newNetType].isDefault()) {
@@ -2169,15 +2226,26 @@
}
}
+ if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info);
thisNet.captivePortalCheckComplete();
}
/** @hide */
+ @Override
public void captivePortalCheckComplete(NetworkInfo info) {
enforceConnectivityInternalPermission();
+ if (DBG) log("captivePortalCheckComplete: ni=" + info);
mNetTrackers[info.getType()].captivePortalCheckComplete();
}
+ /** @hide */
+ @Override
+ public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
+ enforceConnectivityInternalPermission();
+ if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal);
+ mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
+ }
+
/**
* Setup data activity tracking for the given network interface.
*
@@ -2238,6 +2306,10 @@
*/
private void handleConnectivityChange(int netType, boolean doReset) {
int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+ if (VDBG) {
+ log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset
+ + " resetMask=" + resetMask);
+ }
/*
* If a non-default network is enabled, add the host routes that
@@ -2305,7 +2377,9 @@
boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
if (resetMask != 0 || resetDns) {
+ if (VDBG) log("handleConnectivityChange: resetting");
if (curLp != null) {
+ if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp);
for (String iface : curLp.getAllInterfaceNames()) {
if (TextUtils.isEmpty(iface) == false) {
if (resetMask != 0) {
@@ -2338,6 +2412,7 @@
// Update 464xlat state.
NetworkStateTracker tracker = mNetTrackers[netType];
if (mClat.requiresClat(netType, tracker)) {
+
// If the connection was previously using clat, but is not using it now, stop the clat
// daemon. Normally, this happens automatically when the connection disconnects, but if
// the disconnect is not reported, or if the connection's LinkProperties changed for
@@ -2391,6 +2466,7 @@
for (RouteInfo r : routeDiff.removed) {
if (isLinkDefault || ! r.isDefaultRoute()) {
+ if (VDBG) log("updateRoutes: default remove route r=" + r);
removeRoute(curLp, r, TO_DEFAULT_TABLE);
}
if (isLinkDefault == false) {
@@ -2435,7 +2511,6 @@
// remove the default route unless somebody else has asked for it
String ifaceName = newLp.getInterfaceName();
if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
- if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
mNetd.removeRoute(ifaceName, r);
} catch (Exception e) {
@@ -2725,9 +2800,8 @@
public void handleMessage(Message msg) {
NetworkInfo info;
switch (msg.what) {
- case NetworkStateTracker.EVENT_STATE_CHANGED:
+ case NetworkStateTracker.EVENT_STATE_CHANGED: {
info = (NetworkInfo) msg.obj;
- int type = info.getType();
NetworkInfo.State state = info.getState();
if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
@@ -2737,15 +2811,17 @@
state + "/" + info.getDetailedState());
}
- // After booting we'll check once for mobile provisioning
- // if we've provisioned by and connected.
- if (!mFirstProvisioningCheckStarted
+ // Since mobile has the notion of a network/apn that can be used for
+ // provisioning we need to check every time we're connected as
+ // CaptiveProtalTracker won't detected it because DCT doesn't report it
+ // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its
+ // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which
+ // is received by MDST and sent here as EVENT_STATE_CHANGED.
+ if (ConnectivityManager.isNetworkTypeMobile(info.getType())
&& (0 != Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0))
&& (state == NetworkInfo.State.CONNECTED)) {
- log("check provisioning after booting");
- mFirstProvisioningCheckStarted = true;
- checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null);
+ checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
}
EventLogTags.writeConnectivityStateChanged(
@@ -2757,6 +2833,30 @@
} else if (info.getDetailedState() ==
DetailedState.CAPTIVE_PORTAL_CHECK) {
handleCaptivePortalTrackerCheck(info);
+ } else if (info.getDetailedState() ==
+ DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) {
+ /**
+ * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
+ * for now its an in between network, its a network that
+ * is actually a default network but we don't want it to be
+ * announced as such to keep background applications from
+ * trying to use it. It turns out that some still try so we
+ * take the additional step of clearing any default routes
+ * to the link that may have incorrectly setup by the lower
+ * levels.
+ */
+ LinkProperties lp = getLinkProperties(info.getType());
+ if (DBG) {
+ log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
+ }
+
+ // Clear any default routes setup by the radio so
+ // any activity by applications trying to use this
+ // connection will fail until the provisioning network
+ // is enabled.
+ for (RouteInfo r : lp.getRoutes()) {
+ removeRoute(lp, r, TO_DEFAULT_TABLE);
+ }
} else if (state == NetworkInfo.State.DISCONNECTED) {
handleDisconnect(info);
} else if (state == NetworkInfo.State.SUSPENDED) {
@@ -2775,18 +2875,21 @@
mLockdownTracker.onNetworkInfoChanged(info);
}
break;
- case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
+ }
+ case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
info = (NetworkInfo) msg.obj;
// TODO: Temporary allowing network configuration
// change not resetting sockets.
// @see bug/4455071
handleConnectivityChange(info.getType(), false);
break;
- case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+ }
+ case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
info = (NetworkInfo) msg.obj;
- type = info.getType();
+ int type = info.getType();
updateNetworkSettings(mNetTrackers[type]);
break;
+ }
}
}
}
@@ -3561,72 +3664,153 @@
enabled));
}
+ private boolean isMobileDataStateTrackerReady() {
+ MobileDataStateTracker mdst =
+ (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+ return (mdst != null) && (mdst.isReady());
+ }
+
+ /**
+ * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
+ */
+
+ /**
+ * No connection was possible to the network.
+ */
+ public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
+
+ /**
+ * A connection was made to the internet, all is well.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;
+
+ /**
+ * The mobile network is a provisioning network.
+ * This is an indication of a warm sim on a mobile network.
+ */
+ public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5;
+
+ AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false);
+
@Override
- public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
- final ResultReceiver resultReceiver) {
- log("checkMobileProvisioning: E sendNotification=" + sendNotification
- + " suggestedTimeOutMs=" + suggestedTimeOutMs
- + " resultReceiver=" + resultReceiver);
- enforceChangePermission();
-
- mFirstProvisioningCheckStarted = true;
-
- int timeOutMs = suggestedTimeOutMs;
- if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
- timeOutMs = CheckMp.MAX_TIMEOUT_MS;
- }
-
- // Check that mobile networks are supported
- if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
- || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) {
- log("checkMobileProvisioning: X no mobile network");
- if (resultReceiver != null) {
- resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null);
- }
- return timeOutMs;
- }
+ public int checkMobileProvisioning(int suggestedTimeOutMs) {
+ int timeOutMs = -1;
+ if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs);
+ enforceConnectivityInternalPermission();
final long token = Binder.clearCallingIdentity();
try {
+ timeOutMs = suggestedTimeOutMs;
+ if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
+ timeOutMs = CheckMp.MAX_TIMEOUT_MS;
+ }
+
+ // Check that mobile networks are supported
+ if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
+ || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) {
+ if (DBG) log("checkMobileProvisioning: X no mobile network");
+ return timeOutMs;
+ }
+
+ // If we're already checking don't do it again
+ // TODO: Add a queue of results...
+ if (mIsCheckingMobileProvisioning.getAndSet(true)) {
+ if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment");
+ return timeOutMs;
+ }
+
+ // Start off with notification off
+ setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
+
+ // See if we've alreadying determined if we've got a provsioning connection
+ // if so we don't need to do anything active
+ MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
+
+ MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+ boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
+
+ if (isDefaultProvisioning || isHipriProvisioning) {
+ if (mIsNotificationVisible) {
+ if (DBG) {
+ log("checkMobileProvisioning: provisioning-ignore notification is visible");
+ }
+ } else {
+ NetworkInfo ni = null;
+ if (isDefaultProvisioning) {
+ ni = mdstDefault.getNetworkInfo();
+ }
+ if (isHipriProvisioning) {
+ ni = mdstHipri.getNetworkInfo();
+ }
+ String url = getMobileProvisioningUrl();
+ if ((ni != null) && (!TextUtils.isEmpty(url))) {
+ setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url);
+ } else {
+ if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore");
+ }
+ }
+ mIsCheckingMobileProvisioning.set(false);
+ return timeOutMs;
+ }
+
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);
- }
+ if (DBG) log("CheckMp.onComplete: result=" + result);
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");
+ case CMP_RESULT_CODE_CONNECTABLE:
+ case CMP_RESULT_CODE_NO_CONNECTION: {
+ if (DBG) log("CheckMp.onComplete: ignore, connected or no connection");
break;
}
- case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
- log("CheckMp.onComplete: warm sim");
+ case CMP_RESULT_CODE_REDIRECTED: {
+ if (DBG) log("CheckMp.onComplete: warm sim");
String url = getMobileProvisioningUrl();
if (TextUtils.isEmpty(url)) {
url = getMobileRedirectedProvisioningUrl();
}
if (TextUtils.isEmpty(url) == false) {
- log("CheckMp.onComplete: warm sim (redirected), url=" + url);
- setNotificationVisible(true, ni, url);
+ if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url);
+ setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(),
+ url);
} else {
- log("CheckMp.onComplete: warm sim (redirected), no url");
+ if (DBG) log("CheckMp.onComplete: warm (redirected), no url");
}
break;
}
- case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
- case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
+ case CMP_RESULT_CODE_NO_DNS:
+ case CMP_RESULT_CODE_NO_TCP_CONNECTION: {
String url = getMobileProvisioningUrl();
if (TextUtils.isEmpty(url) == false) {
- log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
- setNotificationVisible(true, ni, url);
+ if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url);
+ setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(),
+ url);
} else {
- log("CheckMp.onComplete: warm sim (no dns/tcp), no url");
+ if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
}
break;
}
@@ -3635,16 +3819,16 @@
break;
}
}
+ mIsCheckingMobileProvisioning.set(false);
}
};
CheckMp.Params params =
new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
- log("checkMobileProvisioning: params=" + params);
- setNotificationVisible(false, null, null);
+ if (DBG) log("checkMobileProvisioning: params=" + params);
checkMp.execute(params);
} finally {
Binder.restoreCallingIdentity(token);
- log("checkMobileProvisioning: X");
+ if (DBG) log("checkMobileProvisioning: X");
}
return timeOutMs;
}
@@ -3716,27 +3900,54 @@
* a known address that fetches the data we expect.
*/
private synchronized Integer isMobileOk(Params params) {
- Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ Integer result = CMP_RESULT_CODE_NO_CONNECTION;
Uri orgUri = Uri.parse(params.mUrl);
Random rand = new Random();
mParams = params;
+ if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
+ log("isMobileOk: not mobile capable");
+ result = CMP_RESULT_CODE_NO_CONNECTION;
+ return result;
+ }
+
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;
+
+ if (!mCs.isMobileDataStateTrackerReady()) {
+ // Wait for MobileDataStateTracker to be ready.
+ if (DBG) log("isMobileOk: mdst is not ready");
+ while(SystemClock.elapsedRealtime() < endTime) {
+ if (mCs.isMobileDataStateTrackerReady()) {
+ // Enable fail fast as we'll do retries here and use a
+ // hipri connection so the default connection stays active.
+ if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data");
+ mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
+ break;
+ }
+ sleep(1);
+ }
+ }
+
+ log("isMobileOk: start hipri url=" + params.mUrl);
+
+ // First wait until we can start using hipri
+ Binder binder = new Binder();
+ while(SystemClock.elapsedRealtime() < endTime) {
+ int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_HIPRI, binder);
+ if ((ret == PhoneConstants.APN_ALREADY_ACTIVE)
+ || (ret == PhoneConstants.APN_REQUEST_STARTED)) {
+ log("isMobileOk: hipri started");
+ break;
+ }
+ if (VDBG) log("isMobileOk: hipri not started yet");
+ result = CMP_RESULT_CODE_NO_CONNECTION;
+ sleep(1);
+ }
+
+ // Continue trying to connect until time has run out
while(SystemClock.elapsedRealtime() < endTime) {
try {
// Wait for hipri to connect.
@@ -3745,13 +3956,26 @@
NetworkInfo.State state = mCs
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (state != NetworkInfo.State.CONNECTED) {
- log("isMobileOk: not connected ni=" +
+ if (true/*VDBG*/) {
+ log("isMobileOk: not connected ni=" +
mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+ }
sleep(1);
- result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ result = CMP_RESULT_CODE_NO_CONNECTION;
continue;
}
+ // Hipri has started check if this is a provisioning url
+ MobileDataStateTracker mdst = (MobileDataStateTracker)
+ mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
+ if (mdst.isProvisioningNetwork()) {
+ if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn");
+ result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
+ return result;
+ } else {
+ if (DBG) log("isMobileOk: isProvisioningNetwork is false, 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
@@ -3762,7 +3986,7 @@
addresses = InetAddress.getAllByName(orgUri.getHost());
} catch (UnknownHostException e) {
log("isMobileOk: UnknownHostException");
- result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS;
+ result = CMP_RESULT_CODE_NO_DNS;
return result;
}
log("isMobileOk: addresses=" + inetAddressesToString(addresses));
@@ -3827,9 +4051,9 @@
urlConn.setRequestProperty("Connection", "close");
int responseCode = urlConn.getResponseCode();
if (responseCode == 204) {
- result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE;
+ result = CMP_RESULT_CODE_CONNECTABLE;
} else {
- result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED;
+ result = CMP_RESULT_CODE_REDIRECTED;
}
log("isMobileOk: connected responseCode=" + responseCode);
urlConn.disconnect();
@@ -3843,7 +4067,7 @@
}
}
}
- result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION;
+ result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
log("isMobileOk: loops|timed out");
return result;
} catch (Exception e) {
@@ -3857,6 +4081,23 @@
mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
Phone.FEATURE_ENABLE_HIPRI);
+
+ // Wait for hipri to disconnect.
+ long endTime = SystemClock.elapsedRealtime() + 5000;
+
+ while(SystemClock.elapsedRealtime() < endTime) {
+ NetworkInfo.State state = mCs
+ .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
+ if (state != NetworkInfo.State.DISCONNECTED) {
+ if (VDBG) {
+ log("isMobileOk: connected ni=" +
+ mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+ }
+ sleep(1);
+ continue;
+ }
+ }
+
log("isMobileOk: X result=" + result);
}
return result;
@@ -3936,10 +4177,55 @@
}
}
- private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+ // TODO: Move to ConnectivityManager and make public?
+ private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION =
+ "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION";
- private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) {
- log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url);
+ private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) {
+ handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL"));
+ }
+ }
+ };
+
+ private void handleMobileProvisioningAction(String url) {
+ // Notication mark notification as not visible
+ setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null);
+
+ // If provisioning network handle as a special case,
+ // otherwise launch browser with the intent directly.
+ NetworkInfo ni = getProvisioningNetworkInfo();
+ if ((ni != null) && ni.getDetailedState() ==
+ NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) {
+ if (DBG) log("handleMobileProvisioningAction: on provisioning network");
+ MobileDataStateTracker mdst = (MobileDataStateTracker)
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ mdst.enableMobileProvisioning(url);
+ } else {
+ if (DBG) log("handleMobileProvisioningAction: on default network");
+ Intent newIntent =
+ new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(newIntent);
+ } catch (ActivityNotFoundException e) {
+ loge("handleMobileProvisioningAction: startActivity failed" + e);
+ }
+ }
+ }
+
+ private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+ private volatile boolean mIsNotificationVisible = false;
+
+ private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo,
+ String url) {
+ if (DBG) {
+ log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType
+ + " extraInfo=" + extraInfo + " url=" + url);
+ }
Resources r = Resources.getSystem();
NotificationManager notificationManager = (NotificationManager) mContext
@@ -3949,50 +4235,64 @@
CharSequence title;
CharSequence details;
int icon;
- switch (networkInfo.getType()) {
+ Intent intent;
+ Notification notification = new Notification();
+ switch (networkType) {
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());
+ extraInfo);
icon = R.drawable.stat_notify_wifi_in_range;
+ 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);
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;
+ intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
+ intent.putExtra("EXTRA_URL", url);
+ intent.setFlags(0);
+ notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
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());
+ extraInfo);
icon = R.drawable.stat_notify_rssi_in_range;
+ 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);
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);
+ try {
+ notificationManager.notify(NOTIFICATION_ID, 1, notification);
+ } catch (NullPointerException npe) {
+ loge("setNotificaitionVisible: visible notificationManager npe=" + npe);
+ npe.printStackTrace();
+ }
} else {
- log("setNotificaitionVisible: cancel");
- notificationManager.cancel(NOTIFICATION_ID, 1);
+ try {
+ notificationManager.cancel(NOTIFICATION_ID, 1);
+ } catch (NullPointerException npe) {
+ loge("setNotificaitionVisible: cancel notificationManager npe=" + npe);
+ npe.printStackTrace();
+ }
}
- log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
+ mIsNotificationVisible = visible;
}
/** Location to an updatable file listing carrier provisioning urls.
@@ -4086,7 +4386,9 @@
return null;
}
- private String getMobileRedirectedProvisioningUrl() {
+ @Override
+ public String getMobileRedirectedProvisioningUrl() {
+ enforceConnectivityInternalPermission();
String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING);
if (TextUtils.isEmpty(url)) {
url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url);
@@ -4094,14 +4396,15 @@
return url;
}
+ @Override
public String getMobileProvisioningUrl() {
enforceConnectivityInternalPermission();
String url = getProvisioningUrlBaseFromFile(PROVISIONING);
if (TextUtils.isEmpty(url)) {
url = mContext.getResources().getString(R.string.mobile_provisioning_url);
- log("getProvisioningUrl: mobile_provisioining_url from resource =" + url);
+ log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url);
} else {
- log("getProvisioningUrl: mobile_provisioning_url from File =" + url);
+ log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url);
}
// populate the iccid, imei and phone number in the provisioning url.
if (!TextUtils.isEmpty(url)) {
@@ -4117,4 +4420,11 @@
return url;
}
+
+ @Override
+ public void setProvisioningNotificationVisible(boolean visible, int networkType,
+ String extraInfo, String url) {
+ enforceConnectivityInternalPermission();
+ setProvNotificationVisible(visible, networkType, extraInfo, url);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 4d8342c..eb93e9c 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -94,6 +94,8 @@
public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
public static final int CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA = BASE + 36;
+ public static final int CMD_ENABLE_MOBILE_PROVISIONING = BASE + 37;
+ public static final int CMD_IS_PROVISIONING_APN = BASE + 38;
/***** Constants *****/
@@ -112,4 +114,5 @@
public static final int ENABLED = 1;
public static final String APN_TYPE_KEY = "apnType";
+ public static final String PROVISIONING_URL_KEY = "provisioningUrl";
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 3cfd0bf..40a3c8f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -145,6 +145,29 @@
public static final String ACTION_ANY_DATA_CONNECTION_STATE_CHANGED
= "android.intent.action.ANY_DATA_STATE";
+ /**
+ * Broadcast Action: Occurs when a data connection connects to a provisioning apn
+ * and is broadcast by the low level data connection code.
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>apn</em> - A string that is the APN associated with this
+ * connection.</li>
+ * <li><em>apnType</em> - A string array of APN types associated with
+ * this connection. The APN type <code>"*"</code> is a special
+ * type that means this APN services all types.</li>
+ * <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li>
+ * <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li>
+ * <li><em>iface</em> - A string that is the name of the interface</li>
+ * </ul>
+ *
+ * <p class="note">
+ * Requires the READ_PHONE_STATE permission.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN
+ = "android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN";
/**
* Broadcast Action: An attempt to establish a data connection has failed.
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0077354..6589ff5 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -3166,6 +3166,7 @@
class VerifyingLinkState extends State {
@Override
public void enter() {
+ log(getName() + " enter");
setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
sendNetworkStateChangeBroadcast(mLastBssid);
@@ -3175,11 +3176,14 @@
switch (message.what) {
case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
//stay here
+ log(getName() + " POOR_LINK_DETECTED: no transition");
break;
case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
+ log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check");
transitionTo(mCaptivePortalCheckState);
break;
default:
+ log(getName() + " what=" + message.what + " NOT_HANDLED");
return NOT_HANDLED;
}
return HANDLED;
@@ -3189,6 +3193,7 @@
class CaptivePortalCheckState extends State {
@Override
public void enter() {
+ log(getName() + " enter");
setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK);
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK);
sendNetworkStateChangeBroadcast(mLastBssid);
@@ -3197,6 +3202,7 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_CAPTIVE_CHECK_COMPLETE:
+ log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE");
try {
mNwService.enableIpv6(mInterfaceName);
} catch (RemoteException re) {
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index cf75381..461dedb 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -120,6 +120,11 @@
mWifiManager.captivePortalCheckComplete();
}
+ @Override
+ public void captivePortalCheckCompleted(boolean isCaptivePortal) {
+ // not implemented
+ }
+
/**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}