summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorWink Saville <wink@google.com>2013-06-29 21:10:57 -0700
committerWink Saville <wink@google.com>2013-06-29 21:10:57 -0700
commitab9321d13de29cf314e8a1774b592d1f1d7e94d8 (patch)
tree3ddf662a65410572a2d0634252212a383e7f840f /services
parent99e4a0f576bad57782b31f1b3329a3d2408f42ae (diff)
downloadframeworks_base-ab9321d13de29cf314e8a1774b592d1f1d7e94d8.zip
frameworks_base-ab9321d13de29cf314e8a1774b592d1f1d7e94d8.tar.gz
frameworks_base-ab9321d13de29cf314e8a1774b592d1f1d7e94d8.tar.bz2
Add checkMobileProvisioning to ConnectivityService.
Bug: 9279964 Change-Id: I42c326a21e05aa301e9d974ed9ac1d59472780ec
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/ConnectivityService.java512
1 files changed, 509 insertions, 3 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 37a8cb8..9e9253a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -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;
+ }
}