1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.tv.settings.connectivity; 18 19 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected; 20 21 import android.app.tvsettings.TvSettingsEnums; 22 import android.content.Context; 23 import android.net.IpConfiguration.IpAssignment; 24 import android.net.IpConfiguration.ProxySettings; 25 import android.net.wifi.WifiConfiguration; 26 import android.net.wifi.WifiInfo; 27 import android.net.wifi.WifiManager; 28 import android.os.Bundle; 29 import android.text.TextUtils; 30 31 import androidx.annotation.NonNull; 32 import androidx.leanback.app.GuidedStepFragment; 33 import androidx.leanback.widget.GuidanceStylist; 34 import androidx.leanback.widget.GuidedAction; 35 import androidx.preference.ListPreference; 36 import androidx.preference.Preference; 37 38 import com.android.internal.logging.nano.MetricsProto; 39 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 40 import com.android.settingslib.wifi.AccessPoint; 41 import com.android.tv.settings.R; 42 import com.android.tv.settings.SettingsPreferenceFragment; 43 44 import java.util.List; 45 46 /** 47 * Fragment for displaying the details of a single wifi network 48 */ 49 public class WifiDetailsFragment extends SettingsPreferenceFragment 50 implements ConnectivityListener.Listener, ConnectivityListener.WifiNetworkListener { 51 52 private static final String ARG_ACCESS_POINT_STATE = "apBundle"; 53 54 private static final String KEY_CONNECTION_STATUS = "connection_status"; 55 private static final String KEY_IP_ADDRESS = "ip_address"; 56 private static final String KEY_MAC_ADDRESS = "mac_address"; 57 private static final String KEY_SIGNAL_STRENGTH = "signal_strength"; 58 private static final String KEY_RANDOM_MAC = "random_mac"; 59 private static final String KEY_PROXY_SETTINGS = "proxy_settings"; 60 private static final String KEY_IP_SETTINGS = "ip_settings"; 61 private static final String KEY_FORGET_NETWORK = "forget_network"; 62 63 private static final String VALUE_MAC_RANDOM = "random"; 64 private static final String VALUE_MAC_DEVICE = "device"; 65 66 private Preference mConnectionStatusPref; 67 private Preference mIpAddressPref; 68 private Preference mMacAddressPref; 69 private Preference mSignalStrengthPref; 70 private ListPreference mRandomMacPref; 71 private Preference mProxySettingsPref; 72 private Preference mIpSettingsPref; 73 private Preference mForgetNetworkPref; 74 75 private ConnectivityListener mConnectivityListener; 76 private AccessPoint mAccessPoint; 77 prepareArgs(@onNull Bundle args, AccessPoint accessPoint)78 public static void prepareArgs(@NonNull Bundle args, AccessPoint accessPoint) { 79 final Bundle apBundle = new Bundle(); 80 accessPoint.saveWifiState(apBundle); 81 args.putParcelable(ARG_ACCESS_POINT_STATE, apBundle); 82 } 83 84 @Override getMetricsCategory()85 public int getMetricsCategory() { 86 return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS; 87 } 88 89 @Override onCreate(Bundle savedInstanceState)90 public void onCreate(Bundle savedInstanceState) { 91 mConnectivityListener = new ConnectivityListener(getContext(), this, getLifecycle()); 92 mAccessPoint = new AccessPoint(getContext(), 93 getArguments().getBundle(ARG_ACCESS_POINT_STATE)); 94 super.onCreate(savedInstanceState); 95 } 96 97 @Override onStart()98 public void onStart() { 99 super.onStart(); 100 mConnectivityListener.setWifiListener(this); 101 } 102 103 @Override onResume()104 public void onResume() { 105 super.onResume(); 106 update(); 107 } 108 109 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)110 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 111 setPreferencesFromResource(R.xml.wifi_details, null); 112 113 getPreferenceScreen().setTitle(mAccessPoint.getSsid()); 114 115 mConnectionStatusPref = findPreference(KEY_CONNECTION_STATUS); 116 mIpAddressPref = findPreference(KEY_IP_ADDRESS); 117 mMacAddressPref = findPreference(KEY_MAC_ADDRESS); 118 mSignalStrengthPref = findPreference(KEY_SIGNAL_STRENGTH); 119 mRandomMacPref = (ListPreference) findPreference(KEY_RANDOM_MAC); 120 mProxySettingsPref = findPreference(KEY_PROXY_SETTINGS); 121 mIpSettingsPref = findPreference(KEY_IP_SETTINGS); 122 mForgetNetworkPref = findPreference(KEY_FORGET_NETWORK); 123 } 124 125 @Override onConnectivityChange()126 public void onConnectivityChange() { 127 update(); 128 } 129 130 @Override onWifiListChanged()131 public void onWifiListChanged() { 132 final List<AccessPoint> accessPoints = mConnectivityListener.getAvailableNetworks(); 133 for (final AccessPoint accessPoint : accessPoints) { 134 if (TextUtils.equals(mAccessPoint.getSsidStr(), accessPoint.getSsidStr()) 135 && mAccessPoint.getSecurity() == accessPoint.getSecurity()) { 136 // Make sure we're not holding on to the one we inflated from the bundle, because 137 // it won't be updated 138 mAccessPoint = accessPoint; 139 break; 140 } 141 } 142 update(); 143 } 144 update()145 private void update() { 146 if (!isAdded()) { 147 return; 148 } 149 150 final boolean active = mAccessPoint.isActive(); 151 152 mConnectionStatusPref.setSummary(active ? R.string.connected : R.string.not_connected); 153 mIpAddressPref.setVisible(active); 154 mSignalStrengthPref.setVisible(active); 155 156 if (active) { 157 mIpAddressPref.setSummary(mConnectivityListener.getWifiIpAddress()); 158 mSignalStrengthPref.setSummary(getSignalStrength()); 159 } 160 161 // Mac address related Preferences (info entry and random mac setting entry) 162 String macAddress = mConnectivityListener.getWifiMacAddress(mAccessPoint); 163 if (active && !TextUtils.isEmpty(macAddress)) { 164 mMacAddressPref.setVisible(true); 165 updateMacAddressPref(macAddress); 166 updateRandomMacPref(); 167 } else { 168 mMacAddressPref.setVisible(false); 169 mRandomMacPref.setVisible(false); 170 } 171 172 WifiConfiguration wifiConfiguration = mAccessPoint.getConfig(); 173 if (wifiConfiguration != null) { 174 final int networkId = wifiConfiguration.networkId; 175 ProxySettings proxySettings = wifiConfiguration.getIpConfiguration().getProxySettings(); 176 mProxySettingsPref.setSummary(proxySettings == ProxySettings.NONE 177 ? R.string.wifi_action_proxy_none : R.string.wifi_action_proxy_manual); 178 mProxySettingsPref.setIntent(EditProxySettingsActivity.createIntent(getContext(), 179 networkId)); 180 181 IpAssignment ipAssignment = wifiConfiguration.getIpConfiguration().getIpAssignment(); 182 mIpSettingsPref.setSummary(ipAssignment == IpAssignment.STATIC 183 ? R.string.wifi_action_static : R.string.wifi_action_dhcp); 184 mIpSettingsPref.setIntent(EditIpSettingsActivity.createIntent(getContext(), networkId)); 185 186 mForgetNetworkPref.setFragment(ForgetNetworkConfirmFragment.class.getName()); 187 ForgetNetworkConfirmFragment.prepareArgs(mForgetNetworkPref.getExtras(), mAccessPoint); 188 } 189 190 mProxySettingsPref.setVisible(wifiConfiguration != null); 191 mProxySettingsPref.setOnPreferenceClickListener( 192 preference -> { 193 logEntrySelected(TvSettingsEnums.NETWORK_AP_INFO_PROXY_SETTINGS); 194 return false; 195 }); 196 mIpSettingsPref.setVisible(wifiConfiguration != null); 197 mIpSettingsPref.setOnPreferenceClickListener( 198 preference -> { 199 logEntrySelected(TvSettingsEnums.NETWORK_AP_INFO_IP_SETTINGS); 200 return false; 201 }); 202 mForgetNetworkPref.setVisible(wifiConfiguration != null); 203 mForgetNetworkPref.setOnPreferenceClickListener( 204 preference -> { 205 logEntrySelected(TvSettingsEnums.NETWORK_AP_INFO_FORGET_NETWORK); 206 return false; 207 }); 208 } 209 getSignalStrength()210 private String getSignalStrength() { 211 String[] signalLevels = getResources().getStringArray(R.array.wifi_signal_strength); 212 int strength = mConnectivityListener.getWifiSignalStrength(signalLevels.length); 213 return signalLevels[strength]; 214 } 215 updateMacAddressPref(String macAddress)216 private void updateMacAddressPref(String macAddress) { 217 if (WifiInfo.DEFAULT_MAC_ADDRESS.equals(macAddress)) { 218 mMacAddressPref.setSummary(R.string.mac_address_not_available); 219 } else { 220 mMacAddressPref.setSummary(macAddress); 221 } 222 if (mAccessPoint == null || mAccessPoint.getConfig() == null) { 223 return; 224 } 225 // For saved Passpoint network, framework doesn't have the field to keep the MAC choice 226 // persistently, so Passpoint network will always use the default value so far, which is 227 // randomized MAC address, so don't need to modify title. 228 if (mAccessPoint.isPasspoint() || mAccessPoint.isPasspointConfig()) { 229 return; 230 } 231 mMacAddressPref.setTitle( 232 (mAccessPoint.getConfig().macRandomizationSetting 233 == WifiConfiguration.RANDOMIZATION_PERSISTENT) 234 ? R.string.title_randomized_mac_address 235 : R.string.title_mac_address); 236 } 237 updateRandomMacPref()238 private void updateRandomMacPref() { 239 mRandomMacPref.setVisible(mConnectivityListener.isMacAddressRandomizationSupported()); 240 boolean isMacRandomized = 241 (mConnectivityListener.getWifiMacRandomizationSetting(mAccessPoint) 242 == WifiConfiguration.RANDOMIZATION_PERSISTENT); 243 mRandomMacPref.setValue(isMacRandomized ? VALUE_MAC_RANDOM : VALUE_MAC_DEVICE); 244 if (mAccessPoint.isEphemeral() || mAccessPoint.isPasspoint() 245 || mAccessPoint.isPasspointConfig()) { 246 mRandomMacPref.setSelectable(false); 247 mRandomMacPref.setSummary(R.string.mac_address_ephemeral_summary); 248 } else { 249 mRandomMacPref.setSelectable(true); 250 mRandomMacPref.setSummary(mRandomMacPref.getEntries()[isMacRandomized ? 0 : 1]); 251 } 252 mRandomMacPref.setOnPreferenceChangeListener( 253 (pref, newValue) -> { 254 mConnectivityListener.applyMacRandomizationSetting( 255 mAccessPoint, 256 VALUE_MAC_RANDOM.equals(newValue)); 257 // The above call should trigger a connectivity change which will refresh 258 // the UI. 259 return true; 260 }); 261 } 262 263 @Override getPageId()264 protected int getPageId() { 265 return TvSettingsEnums.NETWORK_AP_INFO; 266 } 267 268 public static class ForgetNetworkConfirmFragment extends GuidedStepFragment { 269 270 private AccessPoint mAccessPoint; 271 private final MetricsFeatureProvider mMetricsFeatureProvider = new MetricsFeatureProvider(); 272 prepareArgs(@onNull Bundle args, AccessPoint accessPoint)273 public static void prepareArgs(@NonNull Bundle args, AccessPoint accessPoint) { 274 final Bundle apBundle = new Bundle(); 275 accessPoint.saveWifiState(apBundle); 276 args.putParcelable(ARG_ACCESS_POINT_STATE, apBundle); 277 } 278 279 @Override onCreate(Bundle savedInstanceState)280 public void onCreate(Bundle savedInstanceState) { 281 mAccessPoint = new AccessPoint(getContext(), 282 getArguments().getBundle(ARG_ACCESS_POINT_STATE)); 283 super.onCreate(savedInstanceState); 284 } 285 286 @NonNull 287 @Override onCreateGuidance(Bundle savedInstanceState)288 public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { 289 return new GuidanceStylist.Guidance( 290 getString(R.string.wifi_forget_network), 291 getString(R.string.wifi_forget_network_description), 292 mAccessPoint.getSsidStr(), 293 getContext().getDrawable(R.drawable.ic_wifi_signal_4_white_132dp)); 294 } 295 296 @Override onCreateActions(@onNull List<GuidedAction> actions, Bundle savedInstanceState)297 public void onCreateActions(@NonNull List<GuidedAction> actions, 298 Bundle savedInstanceState) { 299 final Context context = getContext(); 300 actions.add(new GuidedAction.Builder(context) 301 .clickAction(GuidedAction.ACTION_ID_OK) 302 .build()); 303 actions.add(new GuidedAction.Builder(context) 304 .clickAction(GuidedAction.ACTION_ID_CANCEL) 305 .build()); 306 } 307 308 @Override onGuidedActionClicked(GuidedAction action)309 public void onGuidedActionClicked(GuidedAction action) { 310 if (action.getId() == GuidedAction.ACTION_ID_OK) { 311 WifiManager wifiManager = 312 (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); 313 wifiManager.forget(mAccessPoint.getConfig().networkId, null); 314 mMetricsFeatureProvider.action( 315 getContext(), MetricsProto.MetricsEvent.ACTION_WIFI_FORGET); 316 } 317 getFragmentManager().popBackStack(); 318 } 319 } 320 } 321