From b46a9194fe88a26e80d415919d191703c340925e Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Mon, 3 Nov 2014 18:47:28 -0800 Subject: [PATCH] Show accurate connection status for ephemeral networks. Configurations for these networks are not returned in getConfiguredNetworks() and likely shouldn't be as clients of this API would not expect them. (Note also that the ephemeral bit is marked @hide). But the framework may connect to them regardless. In these cases, as long as the connection status is something other than the coarse-level DISCONNECTED, we show the status to be an accurate representation of Wi-Fi state. (To make this possible, we pass around the full NetworkInfo instead of just the DetailedState, allowing us to get the coarse state where needed). When long pressing on a non-DISCONNECTED ephemeral network, we offer the ability to save the configuration. (Note that this flow is currently broken and being tracked by another bug, but the behavior is consistent with what happens when you simply click on the SSID). Bug: 18205278 Change-Id: I30592c89546068c796f458a86bb26eb3b28c64df --- res/values/strings.xml | 2 + src/com/android/settings/wifi/AccessPoint.java | 78 +++++++++++++++++-------- src/com/android/settings/wifi/WifiSettings.java | 51 +++++++++++----- 3 files changed, 92 insertions(+), 39 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 25bacb3c37..fbf37abbd4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1505,6 +1505,8 @@ Advanced Connect to network + + Remember network Forget network diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java index ffd4bf3048..6b6175e27e 100644 --- a/src/com/android/settings/wifi/AccessPoint.java +++ b/src/com/android/settings/wifi/AccessPoint.java @@ -21,7 +21,9 @@ import com.android.settings.R; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; +import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; @@ -70,7 +72,7 @@ class AccessPoint extends Preference { public LruCache mScanResultCache; - private static final String KEY_DETAILEDSTATE = "key_detailedstate"; + private static final String KEY_NETWORKINFO = "key_networkinfo"; private static final String KEY_WIFIINFO = "key_wifiinfo"; private static final String KEY_SCANRESULT = "key_scanresult"; private static final String KEY_CONFIG = "key_config"; @@ -113,7 +115,8 @@ class AccessPoint extends Preference { private long mSeen = 0; private WifiInfo mInfo; - private DetailedState mState; + private NetworkInfo mNetworkInfo; + private TextView mSummaryView; private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000; private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000; @@ -211,18 +214,18 @@ class AccessPoint extends Preference { loadResult(mScanResult); } mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO); - if (savedState.containsKey(KEY_DETAILEDSTATE)) { - mState = DetailedState.valueOf(savedState.getString(KEY_DETAILEDSTATE)); + if (savedState.containsKey(KEY_NETWORKINFO)) { + mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO); } - update(mInfo, mState); + update(mInfo, mNetworkInfo); } public void saveWifiState(Bundle savedState) { savedState.putParcelable(KEY_CONFIG, mConfig); savedState.putParcelable(KEY_SCANRESULT, mScanResult); savedState.putParcelable(KEY_WIFIINFO, mInfo); - if (mState != null) { - savedState.putString(KEY_DETAILEDSTATE, mState.toString()); + if (mNetworkInfo != null) { + savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo); } } @@ -253,9 +256,8 @@ class AccessPoint extends Preference { super.onBindView(view); updateIcon(getLevel(), getContext()); - final TextView summaryView = (TextView) view.findViewById( - com.android.internal.R.id.summary); - summaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); + mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); + mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); notifyChanged(); } @@ -293,8 +295,8 @@ class AccessPoint extends Preference { } AccessPoint other = (AccessPoint) preference; // Active one goes first. - if (mInfo != null && other.mInfo == null) return -1; - if (mInfo == null && other.mInfo != null) return 1; + if (isActive() && !other.isActive()) return -1; + if (!isActive() && other.isActive()) return 1; // Reachable one goes before unreachable one. if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1; @@ -361,19 +363,30 @@ class AccessPoint extends Preference { return false; } - void update(WifiInfo info, DetailedState state) { + /** Return whether the given {@link WifiInfo} is for this access point. */ + private boolean isInfoForThisAccessPoint(WifiInfo info) { + if (networkId != WifiConfiguration.INVALID_NETWORK_ID) { + return networkId == info.getNetworkId(); + } else { + // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID. + // (Note that we only do this if the WifiConfiguration explicitly equals INVALID). + // TODO: Handle hex string SSIDs. + return ssid.equals(removeDoubleQuotes(info.getSSID())); + } + } + + void update(WifiInfo info, NetworkInfo networkInfo) { boolean reorder = false; - if (info != null && networkId != WifiConfiguration.INVALID_NETWORK_ID - && networkId == info.getNetworkId()) { + if (info != null && isInfoForThisAccessPoint(info)) { reorder = (mInfo == null); mRssi = info.getRssi(); mInfo = info; - mState = state; + mNetworkInfo = networkInfo; refresh(); } else if (mInfo != null) { reorder = true; mInfo = null; - mState = null; + mNetworkInfo = null; refresh(); } if (reorder) { @@ -396,8 +409,12 @@ class AccessPoint extends Preference { return mInfo; } + NetworkInfo getNetworkInfo() { + return mNetworkInfo; + } + DetailedState getState() { - return mState; + return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null; } static String removeDoubleQuotes(String string) { @@ -418,8 +435,11 @@ class AccessPoint extends Preference { * * @param showSummary true will show the summary, false will hide the summary */ - public void setShowSummary(boolean showSummary){ + public void setShowSummary(boolean showSummary) { this.showSummary = showSummary; + if (mSummaryView != null) { + mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); + } // otherwise, will be handled in onBindView. } /** @@ -571,6 +591,17 @@ class AccessPoint extends Preference { } /** + * Return whether this is the active connection. + * For ephemeral connections (networkId is invalid), this returns false if the network is + * disconnected. + */ + private boolean isActive() { + return mNetworkInfo != null && + (networkId != WifiConfiguration.INVALID_NETWORK_ID || + mNetworkInfo.getState() != State.DISCONNECTED); + } + + /** * Updates the title and summary; may indirectly call notifyChanged(). */ private void refresh() { @@ -585,8 +616,8 @@ class AccessPoint extends Preference { // Update to new summary StringBuilder summary = new StringBuilder(); - if (mState != null) { // This is the active connection - summary.append(Summary.get(context, mState)); + if (isActive()) { + summary.append(Summary.get(context, getState())); } else if (mConfig != null && mConfig.noInternetAccess) { summary.append(context.getString(R.string.wifi_no_internet)); } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED && @@ -628,7 +659,7 @@ class AccessPoint extends Preference { if (WifiSettings.mVerboseLogging > 0) { //add RSSI/band information for this config, what was seen up to 6 seconds ago //verbose WiFi Logging is only turned on thru developers settings - if (mInfo != null && mState != null) { // This is the active connection + if (mInfo != null && mNetworkInfo != null) { // This is the active connection summary.append(" f=" + Integer.toString(mInfo.getFrequency())); } summary.append(" " + getVisibilityStatus()); @@ -660,8 +691,9 @@ class AccessPoint extends Preference { if (summary.length() > 0) { setSummary(summary.toString()); + setShowSummary(true); } else { - showSummary = false; + setShowSummary(false); } } diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 1ef9cce1c0..76ebcca2d8 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -34,6 +34,7 @@ import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; import android.net.NetworkScoreManager; import android.net.NetworkScorerAppManager; import android.net.NetworkScorerAppManager.NetworkScorerAppData; @@ -132,7 +133,7 @@ public class WifiSettings extends RestrictedSettingsFragment // An access point being editted is stored here. private AccessPoint mSelectedAccessPoint; - private DetailedState mLastState; + private NetworkInfo mLastNetworkInfo; private WifiInfo mLastInfo; private final AtomicBoolean mConnected = new AtomicBoolean(false); @@ -529,9 +530,22 @@ public class WifiSettings extends RestrictedSettingsFragment if (preference instanceof AccessPoint) { mSelectedAccessPoint = (AccessPoint) preference; menu.setHeaderTitle(mSelectedAccessPoint.ssid); - if (mSelectedAccessPoint.getLevel() != -1 - && mSelectedAccessPoint.getState() == null) { - menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); + if (mSelectedAccessPoint.getLevel() != -1) { + int connectStringRes = 0; + if (mSelectedAccessPoint.getState() == null) { + connectStringRes = R.string.wifi_menu_connect; + } else if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID && + mSelectedAccessPoint.getNetworkInfo().getState() + != State.DISCONNECTED) { + // State is non-null (and not disconnected) but this network has no + // configuration, which means it is ephemeral. Allow the user to save the + // configuration permanently (but still issue this as a CONNECT command). + connectStringRes = R.string.wifi_menu_remember; + } + + if (connectStringRes != 0) { + menu.add(Menu.NONE, MENU_ID_CONNECT, 0, connectStringRes); + } } if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) { if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) { @@ -671,7 +685,8 @@ public class WifiSettings extends RestrictedSettingsFragment case WifiManager.WIFI_STATE_ENABLED: // AccessPoints are automatically sorted with TreeSet. final Collection accessPoints = - constructAccessPoints(getActivity(), mWifiManager, mLastInfo, mLastState); + constructAccessPoints(getActivity(), mWifiManager, mLastInfo, + mLastNetworkInfo); getPreferenceScreen().removeAll(); if (accessPoints.size() == 0) { addMessagePreference(R.string.wifi_empty_list_wifi_on); @@ -833,7 +848,7 @@ public class WifiSettings extends RestrictedSettingsFragment /** Returns sorted list of access points */ private static List constructAccessPoints(Context context, - WifiManager wifiManager, WifiInfo lastInfo, DetailedState lastState) { + WifiManager wifiManager, WifiInfo lastInfo, NetworkInfo lastNetworkInfo) { ArrayList accessPoints = new ArrayList(); /** Lookup table to more quickly update AccessPoints by only considering objects with the * correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */ @@ -853,8 +868,8 @@ public class WifiSettings extends RestrictedSettingsFragment continue; } AccessPoint accessPoint = new AccessPoint(context, config); - if (lastInfo != null && lastState != null) { - accessPoint.update(lastInfo, lastState); + if (lastInfo != null && lastNetworkInfo != null) { + accessPoint.update(lastInfo, lastNetworkInfo); } accessPoints.add(accessPoint); apMap.put(accessPoint.ssid, accessPoint); @@ -877,6 +892,9 @@ public class WifiSettings extends RestrictedSettingsFragment } if (!found) { AccessPoint accessPoint = new AccessPoint(context, result); + if (lastInfo != null && lastNetworkInfo != null) { + accessPoint.update(lastInfo, lastNetworkInfo); + } accessPoints.add(accessPoint); apMap.put(accessPoint.ssid, accessPoint); } @@ -903,28 +921,29 @@ public class WifiSettings extends RestrictedSettingsFragment mConnected.set(info.isConnected()); changeNextButtonState(info.isConnected()); updateAccessPoints(); - updateConnectionState(info.getDetailedState()); + updateNetworkInfo(info); } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { - updateConnectionState(null); + updateNetworkInfo(null); } } - private void updateConnectionState(DetailedState state) { + private void updateNetworkInfo(NetworkInfo networkInfo) { /* sticky broadcasts can call this when wifi is disabled */ if (!mWifiManager.isWifiEnabled()) { mScanner.pause(); return; } - if (state == DetailedState.OBTAINING_IPADDR) { + if (networkInfo != null && + networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) { mScanner.pause(); } else { mScanner.resume(); } mLastInfo = mWifiManager.getConnectionInfo(); - if (state != null) { - mLastState = state; + if (networkInfo != null) { + mLastNetworkInfo = networkInfo; } for (int i = getPreferenceScreen().getPreferenceCount() - 1; i >= 0; --i) { @@ -932,7 +951,7 @@ public class WifiSettings extends RestrictedSettingsFragment Preference preference = getPreferenceScreen().getPreference(i); if (preference instanceof AccessPoint) { final AccessPoint accessPoint = (AccessPoint) preference; - accessPoint.update(mLastInfo, mLastState); + accessPoint.update(mLastInfo, mLastNetworkInfo); } } } @@ -958,7 +977,7 @@ public class WifiSettings extends RestrictedSettingsFragment } mLastInfo = null; - mLastState = null; + mLastNetworkInfo = null; mScanner.pause(); } -- 2.11.0