diff options
3 files changed, 184 insertions, 70 deletions
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java index 22d200fc2..21a25ec52 100644 --- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java +++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointNetworkDetailsTracker.java @@ -45,6 +45,7 @@ import java.time.Clock; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; /** * Implementation of NetworkDetailsTracker that tracks a single PasspointWifiEntry. @@ -68,17 +69,32 @@ class PasspointNetworkDetailsTracker extends NetworkDetailsTracker { super(lifecycle, context, wifiManager, connectivityManager, networkScoreManager, mainHandler, workerHandler, clock, maxScanAgeMillis, scanIntervalMillis, TAG); - PasspointConfiguration passpointConfig = mWifiManager.getPasspointConfigurations().stream() - .filter(config -> TextUtils.equals( - uniqueIdToPasspointWifiEntryKey(config.getUniqueId()), key)) - .findAny().get(); - - checkNotNull(passpointConfig, - "Cannot find PasspointConfiguration with matching unique identifier: " - + passpointConfig.getUniqueId()); + Optional<PasspointConfiguration> optionalPasspointConfig = + mWifiManager.getPasspointConfigurations() + .stream() + .filter(passpointConfig -> TextUtils.equals(key, + uniqueIdToPasspointWifiEntryKey(passpointConfig.getUniqueId()))) + .findAny(); + if (optionalPasspointConfig.isPresent()) { + mChosenEntry = new PasspointWifiEntry(mContext, mMainHandler, + optionalPasspointConfig.get(), mWifiManager, false /* forSavedNetworksPage */); + } else { + Optional<WifiConfiguration> optionalWifiConfig = + mWifiManager.getPrivilegedConfiguredNetworks() + .stream() + .filter(wifiConfig -> wifiConfig.isPasspoint() + && TextUtils.equals(key, + uniqueIdToPasspointWifiEntryKey(wifiConfig.getKey()))) + .findAny(); + if (optionalWifiConfig.isPresent()) { + mChosenEntry = new PasspointWifiEntry(mContext, mMainHandler, + optionalWifiConfig.get(), mWifiManager, false /* forSavedNetworksPage */); + } else { + throw new IllegalArgumentException( + "Cannot find config for given PasspointWifiEntry key!"); + } + } - mChosenEntry = new PasspointWifiEntry(mContext, mMainHandler, passpointConfig, - mWifiManager, false /* forSavedNetworksPage */); cacheNewScanResults(); conditionallyUpdateScanResults(true /* lastScanSucceeded */); conditionallyUpdateConfig(); diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java index 3b2ad3f33..d659151c2 100644 --- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java +++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/PasspointWifiEntry.java @@ -20,8 +20,11 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import static androidx.core.util.Preconditions.checkNotNull; +import static com.android.wifitrackerlib.Utils.getAppLabel; +import static com.android.wifitrackerlib.Utils.getAppLabelForWifiConfiguration; import static com.android.wifitrackerlib.Utils.getAutoConnectDescription; import static com.android.wifitrackerlib.Utils.getBestScanResultByLevel; +import static com.android.wifitrackerlib.Utils.getCarrierNameForSubId; import static com.android.wifitrackerlib.Utils.getCurrentNetworkCapabilitiesInformation; import static com.android.wifitrackerlib.Utils.getDisconnectedStateDescription; import static com.android.wifitrackerlib.Utils.getImsiProtectionDescription; @@ -29,6 +32,7 @@ import static com.android.wifitrackerlib.Utils.getMeteredDescription; import static com.android.wifitrackerlib.Utils.getNetworkDetailedState; import static com.android.wifitrackerlib.Utils.getSecurityTypeFromWifiConfiguration; import static com.android.wifitrackerlib.Utils.getSpeedDescription; +import static com.android.wifitrackerlib.Utils.getSubIdForConfig; import static com.android.wifitrackerlib.Utils.getVerboseLoggingDescription; import android.content.Context; @@ -67,11 +71,13 @@ public class PasspointWifiEntry extends WifiEntry { private final List<ScanResult> mCurrentRoamingScanResults = new ArrayList<>(); @NonNull private final String mKey; + @NonNull private String mFqdn; @NonNull private String mFriendlyName; @NonNull private final Context mContext; - @NonNull private PasspointConfiguration mPasspointConfig; + @Nullable + private PasspointConfiguration mPasspointConfig; @Nullable private WifiConfiguration mWifiConfig; - private @Security int mSecurity; + private @Security int mSecurity = SECURITY_EAP; private boolean mIsRoaming = false; private int mLevel = WIFI_LEVEL_UNREACHABLE; @@ -82,7 +88,7 @@ public class PasspointWifiEntry extends WifiEntry { // For PasspointWifiEntry#getMeteredChoice() to return correct value right after // PasspointWifiEntry#setMeteredChoice(int meteredChoice), cache // PasspointConfiguration#getMeteredOverride() in this variable. - private int mMeteredOverride; + private int mMeteredOverride = METERED_CHOICE_AUTO; /** * Create a PasspointWifiEntry with the associated PasspointConfiguration @@ -98,13 +104,36 @@ public class PasspointWifiEntry extends WifiEntry { mContext = context; mPasspointConfig = passpointConfig; mKey = uniqueIdToPasspointWifiEntryKey(passpointConfig.getUniqueId()); + mFqdn = passpointConfig.getHomeSp().getFqdn(); mFriendlyName = passpointConfig.getHomeSp().getFriendlyName(); - mSecurity = SECURITY_NONE; //TODO: Should this always be Enterprise? mSubscriptionExpirationTimeInMillis = passpointConfig.getSubscriptionExpirationTimeMillis(); mMeteredOverride = mPasspointConfig.getMeteredOverride(); } + /** + * Create a PasspointWifiEntry with the associated WifiConfiguration for use with network + * suggestions, since WifiManager#getAllMatchingWifiConfigs() does not provide a corresponding + * PasspointConfiguration. + */ + PasspointWifiEntry(@NonNull Context context, @NonNull Handler callbackHandler, + @NonNull WifiConfiguration wifiConfig, + @NonNull WifiManager wifiManager, + boolean forSavedNetworksPage) throws IllegalArgumentException { + super(callbackHandler, wifiManager, forSavedNetworksPage); + + checkNotNull(wifiConfig, "Cannot construct with null PasspointConfiguration!"); + if (!wifiConfig.isPasspoint()) { + throw new IllegalArgumentException("Given WifiConfiguration is not for Passpoint!"); + } + + mContext = context; + mWifiConfig = wifiConfig; + mKey = uniqueIdToPasspointWifiEntryKey(wifiConfig.getKey()); + mFqdn = wifiConfig.FQDN; + mFriendlyName = mWifiConfig.providerFriendlyName; + } + @Override public String getKey() { return mKey; @@ -135,7 +164,15 @@ public class PasspointWifiEntry extends WifiEntry { if (concise) { sj.add(mContext.getString(R.string.wifi_disconnected)); } else if (!mForSavedNetworksPage) { - sj.add(mContext.getString(R.string.wifi_remembered)); + if (mWifiConfig != null && mWifiConfig.fromWifiNetworkSuggestion) { + String carrierName = getCarrierNameForSubId(mContext, + getSubIdForConfig(mContext, mWifiConfig)); + sj.add(mContext.getString(R.string.available_via_app, carrierName != null + ? carrierName + : getAppLabelForWifiConfiguration(mContext, mWifiConfig))); + } else { + sj.add(mContext.getString(R.string.wifi_remembered)); + } } } else { sj.add(disconnectDescription); @@ -169,6 +206,17 @@ public class PasspointWifiEntry extends WifiEntry { private String getConnectStateDescription() { if (getConnectedState() == CONNECTED_STATE_CONNECTED) { + // For network suggestions + final String suggestionOrSpecifierPackageName = mWifiInfo != null + ? mWifiInfo.getRequestingPackageName() : null; + if (!TextUtils.isEmpty(suggestionOrSpecifierPackageName)) { + String carrierName = mWifiConfig != null + ? getCarrierNameForSubId(mContext, getSubIdForConfig(mContext, mWifiConfig)) + : null; + return mContext.getString(R.string.connected_via_app, carrierName != null + ? carrierName + : getAppLabel(mContext, suggestionOrSpecifierPackageName)); + } String networkCapabilitiesinformation = getCurrentNetworkCapabilitiesInformation(mContext, mNetworkCapabilities); if (!TextUtils.isEmpty(networkCapabilitiesinformation)) { @@ -222,12 +270,12 @@ public class PasspointWifiEntry extends WifiEntry { @Override public boolean isSuggestion() { // TODO(b/70983952): Fill this method in when passpoint suggestions are in - return false; + return mWifiConfig != null && mWifiConfig.fromWifiNetworkSuggestion; } @Override public boolean isSubscription() { - return true; + return mPasspointConfig != null; } @Override @@ -275,11 +323,15 @@ public class PasspointWifiEntry extends WifiEntry { @Override public boolean canForget() { - return true; + return mPasspointConfig != null; } @Override public void forget(@Nullable ForgetCallback callback) { + if (!canForget()) { + return; + } + mForgetCallback = callback; mWifiManager.removePasspointConfiguration(mPasspointConfig.getHomeSp().getFqdn()); new ForgetActionListener().onSuccess(); @@ -333,11 +385,15 @@ public class PasspointWifiEntry extends WifiEntry { @Override public boolean canSetMeteredChoice() { - return true; + return mPasspointConfig != null; } @Override public void setMeteredChoice(int meteredChoice) { + if (!canSetMeteredChoice()) { + return; + } + switch (meteredChoice) { case METERED_CHOICE_AUTO: mMeteredOverride = WifiConfiguration.METERED_OVERRIDE_NONE; @@ -358,18 +414,26 @@ public class PasspointWifiEntry extends WifiEntry { @Override public boolean canSetPrivacy() { - return true; + return mPasspointConfig != null; } @Override @Privacy public int getPrivacy() { + if (mPasspointConfig == null) { + return PRIVACY_RANDOMIZED_MAC; + } + return mPasspointConfig.isMacRandomizationEnabled() ? PRIVACY_RANDOMIZED_MAC : PRIVACY_DEVICE_MAC; } @Override public void setPrivacy(int privacy) { + if (!canSetPrivacy()) { + return; + } + mWifiManager.setMacRandomizationSettingPasspointEnabled( mPasspointConfig.getHomeSp().getFqdn(), privacy == PRIVACY_DEVICE_MAC ? false : true); @@ -377,6 +441,11 @@ public class PasspointWifiEntry extends WifiEntry { @Override public boolean isAutoJoinEnabled() { + // Suggestion network; use WifiConfig instead + if (mPasspointConfig == null && mWifiConfig != null) { + return mWifiConfig.allowAutojoin; + } + return mPasspointConfig.isAutojoinEnabled(); } @@ -387,6 +456,11 @@ public class PasspointWifiEntry extends WifiEntry { @Override public void setAutoJoinEnabled(boolean enabled) { + if (mPasspointConfig == null && mWifiConfig != null) { + mWifiManager.allowAutojoin(mWifiConfig.networkId, enabled); + return; + } + mWifiManager.allowAutojoinPasspoint(mPasspointConfig.getHomeSp().getFqdn(), enabled); } @@ -407,12 +481,14 @@ public class PasspointWifiEntry extends WifiEntry { } @WorkerThread - void updatePasspointConfig(@NonNull PasspointConfiguration passpointConfig) { + void updatePasspointConfig(@Nullable PasspointConfiguration passpointConfig) { mPasspointConfig = passpointConfig; - mFriendlyName = passpointConfig.getHomeSp().getFriendlyName(); - mSubscriptionExpirationTimeInMillis = - passpointConfig.getSubscriptionExpirationTimeMillis(); - mMeteredOverride = mPasspointConfig.getMeteredOverride(); + if (mPasspointConfig != null) { + mFriendlyName = passpointConfig.getHomeSp().getFriendlyName(); + mSubscriptionExpirationTimeInMillis = + passpointConfig.getSubscriptionExpirationTimeMillis(); + mMeteredOverride = passpointConfig.getMeteredOverride(); + } notifyOnUpdated(); } @@ -463,8 +539,8 @@ public class PasspointWifiEntry extends WifiEntry { return false; } - return TextUtils.equals( - wifiInfo.getPasspointFqdn(), mPasspointConfig.getHomeSp().getFqdn()); + // Match with FQDN until WifiInfo supports returning the passpoint uniqueID + return TextUtils.equals(wifiInfo.getPasspointFqdn(), mFqdn); } @NonNull diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java index 33a9b777a..6e74e2eba 100644 --- a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java +++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/WifiPickerTracker.java @@ -67,6 +67,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Wi-Fi tracker that provides all Wi-Fi related data to the Wi-Fi picker page. @@ -107,6 +108,8 @@ public class WifiPickerTracker extends BaseWifiTracker { // Cache containing visible OsuWifiEntries. Must be accessed only by the worker thread. private final Map<String, OsuWifiEntry> mOsuWifiEntryCache = new HashMap<>(); + private int mNumSavedNetworks; + /** * Constructor for WifiPickerTracker. * @@ -164,8 +167,7 @@ public class WifiPickerTracker extends BaseWifiTracker { */ @AnyThread public int getNumSavedNetworks() { - return (int) mWifiConfigCache.values().stream() - .filter(config -> !config.isEphemeral()).count(); + return mNumSavedNetworks; } /** @@ -440,6 +442,7 @@ public class WifiPickerTracker extends BaseWifiTracker { Set<String> seenKeys = new TreeSet<>(); List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingWifiConfigs = mWifiManager.getAllMatchingWifiConfigs(scanResults); + for (Pair<WifiConfiguration, Map<Integer, List<ScanResult>>> pair : matchingWifiConfigs) { final WifiConfiguration wifiConfig = pair.first; final List<ScanResult> homeScans = @@ -448,16 +451,21 @@ public class WifiPickerTracker extends BaseWifiTracker { pair.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK); final String key = uniqueIdToPasspointWifiEntryKey(wifiConfig.getKey()); seenKeys.add(key); - // Skip in case we don't have a Passpoint configuration for the returned unique key - if (!mPasspointConfigCache.containsKey(key)) { - continue; - } // Create PasspointWifiEntry if one doesn't exist for the seen key yet. if (!mPasspointWifiEntryCache.containsKey(key)) { - mPasspointWifiEntryCache.put(key, new PasspointWifiEntry(mContext, - mMainHandler, mPasspointConfigCache.get(key), mWifiManager, - false /* forSavedNetworksPage */)); + if (wifiConfig.fromWifiNetworkSuggestion) { + mPasspointWifiEntryCache.put(key, new PasspointWifiEntry(mContext, + mMainHandler, wifiConfig, mWifiManager, + false /* forSavedNetworksPage */)); + } else if (mPasspointConfigCache.containsKey(key)) { + mPasspointWifiEntryCache.put(key, new PasspointWifiEntry(mContext, + mMainHandler, mPasspointConfigCache.get(key), mWifiManager, + false /* forSavedNetworksPage */)); + } else { + // Failed to find PasspointConfig for a provisioned Passpoint network + continue; + } } mPasspointWifiEntryCache.get(key).updateScanResultInfo(wifiConfig, homeScans, roamingScans); @@ -542,23 +550,31 @@ public class WifiPickerTracker extends BaseWifiTracker { checkNotNull(config, "Config should not be null!"); final String key = wifiConfigToStandardWifiEntryKey(config); - final StandardWifiEntry entry = mStandardWifiEntryCache.get(key); - final StandardWifiEntry suggestedEntry = mSuggestedWifiEntryCache.get(key); - - if (entry != null) { + StandardWifiEntry updatedEntry; + WifiConfiguration updatedConfig; + if (config.fromWifiNetworkSuggestion) { if (changeReason == WifiManager.CHANGE_REASON_REMOVED) { - mWifiConfigCache.remove(key); + mSuggestedConfigCache.remove(key); } else { // CHANGE_REASON_ADDED || CHANGE_REASON_CONFIG_CHANGE - mWifiConfigCache.put(key, config); + mSuggestedConfigCache.put(key, config); } - entry.updateConfig(mWifiConfigCache.get(key)); - } else if (suggestedEntry != null) { + updatedConfig = mSuggestedConfigCache.get(key); + updatedEntry = mSuggestedWifiEntryCache.get(key); + } else { if (changeReason == WifiManager.CHANGE_REASON_REMOVED) { mWifiConfigCache.remove(key); } else { // CHANGE_REASON_ADDED || CHANGE_REASON_CONFIG_CHANGE mWifiConfigCache.put(key, config); } - suggestedEntry.updateConfig(mWifiConfigCache.get(key)); + updatedConfig = mWifiConfigCache.get(key); + updatedEntry = mStandardWifiEntryCache.get(key); + mNumSavedNetworks = (int) mWifiConfigCache.values().stream() + .filter(cachedConfig -> + !cachedConfig.isEphemeral() && !cachedConfig.isPasspoint()).count(); + } + + if (updatedEntry != null) { + updatedEntry.updateConfig(updatedConfig); } } @@ -580,21 +596,28 @@ public class WifiPickerTracker extends BaseWifiTracker { mWifiConfigCache.put(wifiConfigToStandardWifiEntryKey(config), config); } } + mNumSavedNetworks = (int) mWifiConfigCache.values().stream() + .filter(cachedConfig -> + !cachedConfig.isEphemeral() && !cachedConfig.isPasspoint()).count(); // Iterate through current entries and update each entry's config mStandardWifiEntryCache.entrySet().forEach((entry) -> { final StandardWifiEntry wifiEntry = entry.getValue(); final String key = wifiEntry.getKey(); - wifiEntry.updateConfig(mWifiConfigCache.get(key)); + final WifiConfiguration config = mWifiConfigCache.get(key); + if (config != null && config.isPasspoint()) { + return; + } + wifiEntry.updateConfig(config); }); // Iterate through current suggestion entries and update each entry's config mSuggestedWifiEntryCache.entrySet().removeIf((entry) -> { final StandardWifiEntry wifiEntry = entry.getValue(); final String key = wifiEntry.getKey(); - final WifiConfiguration cachedConfig = mSuggestedConfigCache.get(key); - if (cachedConfig != null) { - wifiEntry.updateConfig(cachedConfig); + final WifiConfiguration config = mSuggestedConfigCache.get(key); + if (config != null && !config.isPasspoint()) { + wifiEntry.updateConfig(config); return false; } else { return true; @@ -615,13 +638,8 @@ public class WifiPickerTracker extends BaseWifiTracker { mPasspointWifiEntryCache.entrySet().removeIf((entry) -> { final PasspointWifiEntry wifiEntry = entry.getValue(); final String key = wifiEntry.getKey(); - final PasspointConfiguration cachedConfig = mPasspointConfigCache.get(key); - if (cachedConfig != null) { - wifiEntry.updatePasspointConfig(cachedConfig); - return false; - } else { - return true; - } + wifiEntry.updatePasspointConfig(mPasspointConfigCache.get(key)); + return !wifiEntry.isSubscription() && !wifiEntry.isSuggestion(); }); } @@ -722,20 +740,24 @@ public class WifiPickerTracker extends BaseWifiTracker { return; } - // TODO(b/148556276): This logic will match the fqdn of the connected passpoint network to - // the first PasspointConfiguration found. This may or may not represent the actual - // connection, so we will need to use WifiInfo.getPasspointUniqueId() once it is ready to be - // a public API. - final String connectedFqdn = wifiInfo.getPasspointFqdn(); - mPasspointConfigCache.values().stream() - .filter(config -> - TextUtils.equals(config.getHomeSp().getFqdn(), connectedFqdn) - && !mPasspointWifiEntryCache.containsKey( - uniqueIdToPasspointWifiEntryKey(config.getUniqueId()))) - .findAny().ifPresent(config -> { - final PasspointWifiEntry connectedEntry = - new PasspointWifiEntry(mContext, mMainHandler, config, mWifiManager, - false /* forSavedNetworksPage */); + final int connectedNetId = wifiInfo.getNetworkId(); + Stream.concat(mWifiConfigCache.values().stream(), mSuggestedConfigCache.values().stream()) + .filter(wifiConfig -> + wifiConfig.isPasspoint() && wifiConfig.networkId == connectedNetId + && !mPasspointWifiEntryCache.containsKey( + uniqueIdToPasspointWifiEntryKey(wifiConfig.getKey()))) + .findAny().ifPresent(wifiConfig -> { + PasspointConfiguration passpointConfig = mPasspointConfigCache.get( + uniqueIdToPasspointWifiEntryKey(wifiConfig.getKey())); + PasspointWifiEntry connectedEntry; + if (passpointConfig != null) { + connectedEntry = new PasspointWifiEntry(mContext, mMainHandler, + passpointConfig, mWifiManager, false /* forSavedNetworksPage */); + } else { + // Suggested PasspointWifiEntry without a corresponding Passpoint config + connectedEntry = new PasspointWifiEntry(mContext, mMainHandler, + wifiConfig, mWifiManager, false /* forSavedNetworksPage */); + } connectedEntry.updateConnectionInfo(wifiInfo, networkInfo); mPasspointWifiEntryCache.put(connectedEntry.getKey(), connectedEntry); }); |