diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2015-04-15 11:48:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-15 11:48:22 +0000 |
commit | e9a88a3844d8ea7429aa3a5762a1f345b25ce102 (patch) | |
tree | f1705b090e8e1b92b4e70152f6b1fc0b4f064ad1 | |
parent | fdddb4eb69e719563e604f7dd27ac6999c7844da (diff) | |
parent | 1248dd3c296a94457d5864b7f433335f32490b50 (diff) | |
download | frameworks_base-e9a88a3844d8ea7429aa3a5762a1f345b25ce102.zip frameworks_base-e9a88a3844d8ea7429aa3a5762a1f345b25ce102.tar.gz frameworks_base-e9a88a3844d8ea7429aa3a5762a1f345b25ce102.tar.bz2 |
Merge changes from topic 'no_internet'
* changes:
Add a noInternetAccessExpected boolean to WifiConfiguration.
Prompt if a network without an Internet connection is selected
Give SystemUI the OVERRIDE_WIFI_CONFIG permission.
Add an UNKNOWN_UID constant to WifiConfiguration.
-rw-r--r-- | core/java/android/net/ConnectivityManager.java | 31 | ||||
-rw-r--r-- | core/java/android/net/IConnectivityManager.aidl | 2 | ||||
-rw-r--r-- | core/java/android/net/NetworkAgent.java | 39 | ||||
-rw-r--r-- | core/java/android/net/NetworkMisc.java | 10 | ||||
-rw-r--r-- | packages/SystemUI/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/ConnectivityService.java | 115 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/NetworkAgentInfo.java | 22 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiConfiguration.java | 19 |
8 files changed, 228 insertions, 11 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index da2c5e0..55e39b1 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -286,6 +286,14 @@ public class ConnectivityManager { public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal"; /** + * Action used to display a dialog that asks the user whether to connect to a network that is + * not validated. This intent is used to start the dialog in settings via startActivity. + * + * @hide + */ + public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED"; + + /** * The absence of a connection type. * @hide */ @@ -2455,6 +2463,29 @@ public class ConnectivityManager { } /** + * Informs the system whether it should switch to {@code network} regardless of whether it is + * validated or not. If {@code accept} is true, and the network was explicitly selected by the + * user (e.g., by selecting a Wi-Fi network in the Settings app), then the network will become + * the system default network regardless of any other network that's currently connected. If + * {@code always} is true, then the choice is remembered, so that the next time the user + * connects to this network, the system will switch to it. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} + * + * @param network The network to accept. + * @param accept Whether to accept the network even if unvalidated. + * @param always Whether to remember this choice in the future. + * + * @hide + */ + public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { + try { + mService.setAcceptUnvalidated(network, accept, always); + } catch (RemoteException e) {} + } + + /** * Resets all connectivity manager settings back to factory defaults. * @hide */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3c09978..1aa9c45 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -156,6 +156,8 @@ interface IConnectivityManager void releaseNetworkRequest(in NetworkRequest networkRequest); + void setAcceptUnvalidated(in Network network, boolean accept, boolean always); + int getRestoreDefaultNetworkDelay(int networkType); boolean addVpnAddress(String address, int prefixLength); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 24aaf0d..95ceb2a 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -104,7 +104,7 @@ public abstract class NetworkAgent extends Handler { public static final int EVENT_UID_RANGES_REMOVED = BASE + 6; /** - * Sent by ConnectivitySerice to the NetworkAgent to inform the agent of the + * Sent by ConnectivityService to the NetworkAgent to inform the agent of the * networks status - whether we could use the network or could not, due to * either a bad network configuration (no internet link) or captive portal. * @@ -119,9 +119,21 @@ public abstract class NetworkAgent extends Handler { * Sent by the NetworkAgent to ConnectivityService to indicate this network was * explicitly selected. This should be sent before the NetworkInfo is marked * CONNECTED so it can be given special treatment at that time. + * + * obj = boolean indicating whether to use this network even if unvalidated */ public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8; + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent of + * whether the network should in the future be used even if not validated. + * This decision is made by the user, but it is the network transport's + * responsibility to remember it. + * + * arg1 = 1 if true, 0 if false + */ + public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { this(looper, context, logTag, ni, nc, lp, score, null); @@ -191,6 +203,9 @@ public abstract class NetworkAgent extends Handler { networkStatus(msg.arg1); break; } + case CMD_SAVE_ACCEPT_UNVALIDATED: { + saveAcceptUnvalidated(msg.arg1 != 0); + } } } @@ -258,10 +273,16 @@ public abstract class NetworkAgent extends Handler { /** * Called by the bearer to indicate this network was manually selected by the user. * This should be called before the NetworkInfo is marked CONNECTED so that this - * Network can be given special treatment at that time. + * Network can be given special treatment at that time. If {@code acceptUnvalidated} is + * {@code true}, then the system will switch to this network. If it is {@code false} and the + * network cannot be validated, the system will ask the user whether to switch to this network. + * If the user confirms and selects "don't ask again", then the system will call + * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever + * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement + * {@link #saveAcceptUnvalidated} to respect the user's choice. */ - public void explicitlySelected() { - queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, 0); + public void explicitlySelected(boolean acceptUnvalidated) { + queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, acceptUnvalidated); } /** @@ -290,6 +311,16 @@ public abstract class NetworkAgent extends Handler { protected void networkStatus(int status) { } + /** + * Called when the user asks to remember the choice to use this network even if unvalidated. + * The transport is responsible for remembering the choice, and the next time the user connects + * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. + * This method will only be called if {@link #explicitlySelected} was called with + * {@code acceptUnvalidated} set to {@code false}. + */ + protected void saveAcceptUnvalidated(boolean accept) { + } + protected void log(String s) { Log.d(LOG_TAG, "NetworkAgent: " + s); } diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index b92c9e3..5511a24 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -45,6 +45,13 @@ public class NetworkMisc implements Parcelable { public boolean explicitlySelected; /** + * Set if the user desires to use this network even if it is unvalidated. This field has meaning + * only if {#link explicitlySelected} is true. If it is, this field must also be set to the + * appropriate value based on previous user choice. + */ + public boolean acceptUnvalidated; + + /** * For mobile networks, this is the subscriber ID (such as IMSI). */ public String subscriberId; @@ -56,6 +63,7 @@ public class NetworkMisc implements Parcelable { if (nm != null) { allowBypass = nm.allowBypass; explicitlySelected = nm.explicitlySelected; + acceptUnvalidated = nm.acceptUnvalidated; subscriberId = nm.subscriberId; } } @@ -69,6 +77,7 @@ public class NetworkMisc implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(allowBypass ? 1 : 0); out.writeInt(explicitlySelected ? 1 : 0); + out.writeInt(acceptUnvalidated ? 1 : 0); out.writeString(subscriberId); } @@ -78,6 +87,7 @@ public class NetworkMisc implements Parcelable { NetworkMisc networkMisc = new NetworkMisc(); networkMisc.allowBypass = in.readInt() != 0; networkMisc.explicitlySelected = in.readInt() != 0; + networkMisc.acceptUnvalidated = in.readInt() != 0; networkMisc.subscriberId = in.readString(); return networkMisc; } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 012c84c..a8a4baa 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -53,6 +53,7 @@ <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> + <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1ac1c8a..b5796c9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -161,6 +161,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // How long to wait before putting up a "This network doesn't have an Internet connection, + // connect anyway?" dialog after the user selects a network that doesn't validate. + private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000; + // How long to delay to removal of a pending intent based request. // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS private final int mReleasePendingIntentDelayMs; @@ -324,6 +328,19 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27; + /** + * used to specify whether a network should be used even if unvalidated. + * arg1 = whether to accept the network if it's unvalidated (1 or 0) + * arg2 = whether to remember this choice in the future (1 or 0) + * obj = network + */ + private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28; + + /** + * used to ask the user to confirm a connection to an unvalidated network. + * obj = network + */ + private static final int EVENT_PROMPT_UNVALIDATED = 29; /** Handler used for internal events. */ final private InternalHandler mHandler; @@ -1843,6 +1860,7 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("ERROR: created network explicitly selected."); } nai.networkMisc.explicitlySelected = true; + nai.networkMisc.acceptUnvalidated = (boolean) msg.obj; break; } case NetworkMonitor.EVENT_NETWORK_TESTED: { @@ -1866,6 +1884,9 @@ public class ConnectivityService extends IConnectivityManager.Stub android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), 0, null); + + // TODO: trigger a NetworkCapabilities update so that the dialog can know + // that the network is now validated and close itself. } break; } @@ -2227,6 +2248,91 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { + enforceConnectivityInternalPermission(); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED, + accept ? 1 : 0, always ? 1: 0, network)); + } + + private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) { + if (DBG) log("handleSetAcceptUnvalidated network=" + network + + " accept=" + accept + " always=" + always); + + NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) { + // Nothing to do. + return; + } + + if (nai.everValidated) { + // The network validated while the dialog box was up. Don't make any changes. There's a + // TODO in the dialog code to make it go away if the network validates; once that's + // implemented, taking action here will be confusing. + return; + } + + if (!nai.networkMisc.explicitlySelected) { + Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network"); + } + + if (accept != nai.networkMisc.acceptUnvalidated) { + int oldScore = nai.getCurrentScore(); + nai.networkMisc.acceptUnvalidated = accept; + rematchAllNetworksAndRequests(nai, oldScore); + sendUpdatedScoreToFactories(nai); + } + + if (always) { + nai.asyncChannel.sendMessage( + NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, accept ? 1 : 0); + } + + // TODO: should we also disconnect from the network if accept is false? + } + + private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(EVENT_PROMPT_UNVALIDATED, nai.network), + PROMPT_UNVALIDATED_DELAY_MS); + } + + private void handlePromptUnvalidated(Network network) { + NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + + // Only prompt if the network is unvalidated and was explicitly selected by the user, and if + // we haven't already been told to switch to it regardless of whether it validated or not. + if (nai == null || nai.everValidated || + !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) { + return; + } + + // TODO: What should we do if we've already switched to this network because we had no + // better option? There are two obvious alternatives. + // + // 1. Decide that there's no point prompting because this is our only usable network. + // However, because we didn't prompt, if later on a validated network comes along, we'll + // either a) silently switch to it - bad if the user wanted to connect to stay on this + // unvalidated network - or b) prompt the user at that later time - bad because the user + // might not understand why they are now being prompted. + // + // 2. Always prompt the user, even if we have no other network to use. The user could then + // try to find an alternative network to join (remember, if we got here, then the user + // selected this network manually). This is bad because the prompt isn't really very + // useful. + // + // For now we do #1, but we can revisit that later. + if (isDefaultNetwork(nai)) { + return; + } + + Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK, network); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClassName("com.android.settings", + "com.android.settings.wifi.WifiNoInternetDialog"); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + } + private class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); @@ -2297,6 +2403,14 @@ public class ConnectivityService extends IConnectivityManager.Stub handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1); break; } + case EVENT_SET_ACCEPT_UNVALIDATED: { + handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0); + break; + } + case EVENT_PROMPT_UNVALIDATED: { + handlePromptUnvalidated((Network) msg.obj); + break; + } case EVENT_SYSTEM_READY: { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { nai.networkMonitor.systemReady = true; @@ -4099,6 +4213,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyIfacesChanged(); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); + scheduleUnvalidatedPrompt(networkAgent); if (networkAgent.isVPN()) { // Temporarily disable the default proxy (not global). synchronized (mProxyLock) { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index f3e0bbc..dac0580 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -68,7 +68,10 @@ public class NetworkAgentInfo { private static final int UNVALIDATED_SCORE_PENALTY = 40; // Score for explicitly connected network. - private static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100; + // + // This ensures that a) the explicitly selected network is never trumped by anything else, and + // b) the explicitly selected network is never torn down. + private static final int MAXIMUM_NETWORK_SCORE = 100; // The list of NetworkRequests being satisfied by this Network. public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>(); @@ -120,13 +123,18 @@ public class NetworkAgentInfo { // score. The NetworkScore class would provide a nice place to centralize score constants // so they are not scattered about the transports. - int score = currentScore; + // If this network is explicitly selected and the user has decided to use it even if it's + // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly + // selected and we're trying to see what its score could be. This ensures that we don't tear + // down an explicitly selected network before the user gets a chance to prefer it when + // a higher-scoring network (e.g., Ethernet) is available. + if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { + return MAXIMUM_NETWORK_SCORE; + } + int score = currentScore; if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY; if (score < 0) score = 0; - - if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE; - return score; } @@ -153,7 +161,9 @@ public class NetworkAgentInfo { networkCapabilities + "} Score{" + getCurrentScore() + "} " + "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " + "created{" + created + "} " + - "explicitlySelected{" + networkMisc.explicitlySelected + "} }"; + "explicitlySelected{" + networkMisc.explicitlySelected + "} " + + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + + "}"; } public String name() { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 6ea0db2..c6f2991 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -194,6 +194,9 @@ public class WifiConfiguration implements Parcelable { /** @hide */ public static final int DISABLED_BY_WIFI_MANAGER = 5; + /** @hide */ + public static final int UNKNOWN_UID = -1; + /** * The ID number that the supplicant uses to identify this * network configuration entry. This must be passed as an argument @@ -688,6 +691,14 @@ public class WifiConfiguration implements Parcelable { } /** + * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a + * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to + * this configuration and selects "don't ask again". + * @hide + */ + public boolean noInternetAccessExpected; + + /** * @hide * Last time we blacklisted the configuration */ @@ -1131,7 +1142,10 @@ public class WifiConfiguration implements Parcelable { if (creatorName != null) sbuf.append(" cname=" + creatorName); if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid); if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName); - sbuf.append("userApproved=" + userApprovedAsString(userApproved)); + sbuf.append(" lcuid=" + lastConnectUid); + sbuf.append(" userApproved=" + userApprovedAsString(userApproved)); + sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected); + sbuf.append(" "); if (this.lastConnected != 0) { sbuf.append('\n'); @@ -1542,6 +1556,7 @@ public class WifiConfiguration implements Parcelable { dirty = source.dirty; userApproved = source.userApproved; numNoInternetAccessReports = source.numNoInternetAccessReports; + noInternetAccessExpected = source.noInternetAccessExpected; } } @@ -1620,6 +1635,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0); dest.writeInt(userApproved); dest.writeInt(numNoInternetAccessReports); + dest.writeInt(noInternetAccessExpected ? 1 : 0); } /** Implement the Parcelable interface {@hide} */ @@ -1694,6 +1710,7 @@ public class WifiConfiguration implements Parcelable { config.autoJoinBailedDueToLowRssi = in.readInt() != 0; config.userApproved = in.readInt(); config.numNoInternetAccessReports = in.readInt(); + config.noInternetAccessExpected = in.readInt() != 0; return config; } |