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 android.content.Context; 20 import android.net.wifi.WifiConfiguration; 21 import android.os.Bundle; 22 import android.os.Handler; 23 import android.os.SystemClock; 24 import android.provider.Settings; 25 26 import androidx.annotation.Keep; 27 import androidx.preference.Preference; 28 import androidx.preference.PreferenceCategory; 29 import androidx.preference.PreferenceManager; 30 import androidx.preference.TwoStatePreference; 31 32 import com.android.internal.logging.nano.MetricsProto; 33 import com.android.settingslib.wifi.AccessPoint; 34 import com.android.settingslib.wifi.AccessPointPreference; 35 import com.android.tv.settings.R; 36 import com.android.tv.settings.SettingsPreferenceFragment; 37 38 import java.util.Collection; 39 import java.util.HashSet; 40 import java.util.Set; 41 42 /** 43 * Fragment for controlling network connectivity 44 */ 45 @Keep 46 public class NetworkFragment extends SettingsPreferenceFragment implements 47 ConnectivityListener.Listener, ConnectivityListener.WifiNetworkListener, 48 AccessPoint.AccessPointListener { 49 50 private static final String KEY_WIFI_ENABLE = "wifi_enable"; 51 private static final String KEY_WIFI_LIST = "wifi_list"; 52 private static final String KEY_WIFI_COLLAPSE = "wifi_collapse"; 53 private static final String KEY_WIFI_OTHER = "wifi_other"; 54 private static final String KEY_WIFI_ADD = "wifi_add"; 55 private static final String KEY_WIFI_ALWAYS_SCAN = "wifi_always_scan"; 56 private static final String KEY_ETHERNET = "ethernet"; 57 private static final String KEY_ETHERNET_STATUS = "ethernet_status"; 58 private static final String KEY_ETHERNET_PROXY = "ethernet_proxy"; 59 private static final String KEY_ETHERNET_DHCP = "ethernet_dhcp"; 60 61 private static final int INITIAL_UPDATE_DELAY = 500; 62 63 private ConnectivityListener mConnectivityListener; 64 private AccessPointPreference.UserBadgeCache mUserBadgeCache; 65 66 private TwoStatePreference mEnableWifiPref; 67 private CollapsibleCategory mWifiNetworksCategory; 68 private Preference mCollapsePref; 69 private Preference mAddPref; 70 private TwoStatePreference mAlwaysScan; 71 private PreferenceCategory mEthernetCategory; 72 private Preference mEthernetStatusPref; 73 private Preference mEthernetProxyPref; 74 private Preference mEthernetDhcpPref; 75 76 private final Handler mHandler = new Handler(); 77 private long mNoWifiUpdateBeforeMillis; 78 private Runnable mInitialUpdateWifiListRunnable = new Runnable() { 79 @Override 80 public void run() { 81 mNoWifiUpdateBeforeMillis = 0; 82 updateWifiList(); 83 } 84 }; 85 newInstance()86 public static NetworkFragment newInstance() { 87 return new NetworkFragment(); 88 } 89 90 @Override onCreate(Bundle savedInstanceState)91 public void onCreate(Bundle savedInstanceState) { 92 mConnectivityListener = new ConnectivityListener(getContext(), this, getLifecycle()); 93 mUserBadgeCache = 94 new AccessPointPreference.UserBadgeCache(getContext().getPackageManager()); 95 super.onCreate(savedInstanceState); 96 } 97 98 @Override onStart()99 public void onStart() { 100 super.onStart(); 101 mConnectivityListener.setWifiListener(this); 102 mNoWifiUpdateBeforeMillis = SystemClock.elapsedRealtime() + INITIAL_UPDATE_DELAY; 103 updateWifiList(); 104 } 105 106 @Override onResume()107 public void onResume() { 108 super.onResume(); 109 // There doesn't seem to be an API to listen to everything this could cover, so 110 // tickle it here and hope for the best. 111 updateConnectivity(); 112 } 113 114 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)115 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 116 getPreferenceManager().setPreferenceComparisonCallback( 117 new PreferenceManager.SimplePreferenceComparisonCallback()); 118 setPreferencesFromResource(R.xml.network, null); 119 120 mEnableWifiPref = (TwoStatePreference) findPreference(KEY_WIFI_ENABLE); 121 mWifiNetworksCategory = (CollapsibleCategory) findPreference(KEY_WIFI_LIST); 122 mCollapsePref = findPreference(KEY_WIFI_COLLAPSE); 123 mAddPref = findPreference(KEY_WIFI_ADD); 124 mAlwaysScan = (TwoStatePreference) findPreference(KEY_WIFI_ALWAYS_SCAN); 125 126 mEthernetCategory = (PreferenceCategory) findPreference(KEY_ETHERNET); 127 mEthernetStatusPref = findPreference(KEY_ETHERNET_STATUS); 128 mEthernetProxyPref = findPreference(KEY_ETHERNET_PROXY); 129 mEthernetProxyPref.setIntent(EditProxySettingsActivity.createIntent(getContext(), 130 WifiConfiguration.INVALID_NETWORK_ID)); 131 mEthernetDhcpPref = findPreference(KEY_ETHERNET_DHCP); 132 mEthernetDhcpPref.setIntent(EditIpSettingsActivity.createIntent(getContext(), 133 WifiConfiguration.INVALID_NETWORK_ID)); 134 } 135 136 @Override onPreferenceTreeClick(Preference preference)137 public boolean onPreferenceTreeClick(Preference preference) { 138 if (preference.getKey() == null) { 139 return super.onPreferenceTreeClick(preference); 140 } 141 switch (preference.getKey()) { 142 case KEY_WIFI_ENABLE: 143 mConnectivityListener.setWifiEnabled(mEnableWifiPref.isChecked()); 144 if (mMetricsFeatureProvider != null) { 145 if (mEnableWifiPref.isChecked()) { 146 mMetricsFeatureProvider.action(getContext(), 147 MetricsProto.MetricsEvent.ACTION_WIFI_ON); 148 } else { 149 // Log if user was connected at the time of switching off. 150 mMetricsFeatureProvider.action(getContext(), 151 MetricsProto.MetricsEvent.ACTION_WIFI_OFF, 152 mConnectivityListener.isWifiConnected()); 153 } 154 } 155 return true; 156 case KEY_WIFI_COLLAPSE: 157 final boolean collapse = !mWifiNetworksCategory.isCollapsed(); 158 mCollapsePref.setTitle(collapse 159 ? R.string.wifi_setting_see_all : R.string.wifi_setting_see_fewer); 160 mWifiNetworksCategory.setCollapsed(collapse); 161 return true; 162 case KEY_WIFI_ALWAYS_SCAN: 163 Settings.Global.putInt(getActivity().getContentResolver(), 164 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 165 mAlwaysScan.isChecked() ? 1 : 0); 166 return true; 167 case KEY_ETHERNET_STATUS: 168 return true; 169 case KEY_WIFI_ADD: 170 mMetricsFeatureProvider.action(getActivity(), 171 MetricsProto.MetricsEvent.ACTION_WIFI_ADD_NETWORK); 172 break; 173 } 174 return super.onPreferenceTreeClick(preference); 175 } 176 updateConnectivity()177 private void updateConnectivity() { 178 if (!isAdded()) { 179 return; 180 } 181 182 final boolean wifiEnabled = mConnectivityListener.isWifiEnabledOrEnabling(); 183 mEnableWifiPref.setChecked(wifiEnabled); 184 185 mWifiNetworksCategory.setVisible(wifiEnabled); 186 mCollapsePref.setVisible(wifiEnabled && mWifiNetworksCategory.shouldShowCollapsePref()); 187 mAddPref.setVisible(wifiEnabled); 188 189 if (!wifiEnabled) { 190 updateWifiList(); 191 } 192 193 int scanAlwaysAvailable = 0; 194 try { 195 scanAlwaysAvailable = Settings.Global.getInt(getContext().getContentResolver(), 196 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE); 197 } catch (Settings.SettingNotFoundException e) { 198 // Ignore 199 } 200 mAlwaysScan.setChecked(scanAlwaysAvailable == 1); 201 202 final boolean ethernetAvailable = mConnectivityListener.isEthernetAvailable(); 203 mEthernetCategory.setVisible(ethernetAvailable); 204 mEthernetStatusPref.setVisible(ethernetAvailable); 205 mEthernetProxyPref.setVisible(ethernetAvailable); 206 mEthernetDhcpPref.setVisible(ethernetAvailable); 207 208 if (ethernetAvailable) { 209 final boolean ethernetConnected = 210 mConnectivityListener.isEthernetConnected(); 211 mEthernetStatusPref.setTitle(ethernetConnected 212 ? R.string.connected : R.string.not_connected); 213 mEthernetStatusPref.setSummary(mConnectivityListener.getEthernetIpAddress()); 214 } 215 } 216 updateWifiList()217 private void updateWifiList() { 218 if (!isAdded()) { 219 return; 220 } 221 222 if (!mConnectivityListener.isWifiEnabledOrEnabling()) { 223 mWifiNetworksCategory.removeAll(); 224 mNoWifiUpdateBeforeMillis = 0; 225 return; 226 } 227 228 final long now = SystemClock.elapsedRealtime(); 229 if (mNoWifiUpdateBeforeMillis > now) { 230 mHandler.removeCallbacks(mInitialUpdateWifiListRunnable); 231 mHandler.postDelayed(mInitialUpdateWifiListRunnable, 232 mNoWifiUpdateBeforeMillis - now); 233 return; 234 } 235 236 final int existingCount = mWifiNetworksCategory.getRealPreferenceCount(); 237 final Set<Preference> toRemove = new HashSet<>(existingCount); 238 for (int i = 0; i < existingCount; i++) { 239 toRemove.add(mWifiNetworksCategory.getPreference(i)); 240 } 241 242 final Context themedContext = getPreferenceManager().getContext(); 243 final Collection<AccessPoint> accessPoints = mConnectivityListener.getAvailableNetworks(); 244 int index = 0; 245 for (final AccessPoint accessPoint : accessPoints) { 246 accessPoint.setListener(this); 247 AccessPointPreference pref = (AccessPointPreference) accessPoint.getTag(); 248 if (pref == null) { 249 pref = new AccessPointPreference(accessPoint, themedContext, mUserBadgeCache, 250 false); 251 accessPoint.setTag(pref); 252 } else { 253 toRemove.remove(pref); 254 } 255 if (accessPoint.isActive()) { 256 pref.setFragment(WifiDetailsFragment.class.getName()); 257 WifiDetailsFragment.prepareArgs(pref.getExtras(), accessPoint); 258 pref.setIntent(null); 259 } else { 260 pref.setFragment(null); 261 pref.setIntent(WifiConnectionActivity.createIntent(getContext(), accessPoint)); 262 } 263 pref.setOrder(index++); 264 // Double-adding is harmless 265 mWifiNetworksCategory.addPreference(pref); 266 } 267 268 for (final Preference preference : toRemove) { 269 mWifiNetworksCategory.removePreference(preference); 270 } 271 272 mCollapsePref.setVisible(mWifiNetworksCategory.shouldShowCollapsePref()); 273 } 274 275 @Override onConnectivityChange()276 public void onConnectivityChange() { 277 updateConnectivity(); 278 } 279 280 @Override onWifiListChanged()281 public void onWifiListChanged() { 282 updateWifiList(); 283 } 284 285 @Override onAccessPointChanged(AccessPoint accessPoint)286 public void onAccessPointChanged(AccessPoint accessPoint) { 287 ((AccessPointPreference) accessPoint.getTag()).refresh(); 288 } 289 290 @Override onLevelChanged(AccessPoint accessPoint)291 public void onLevelChanged(AccessPoint accessPoint) { 292 ((AccessPointPreference) accessPoint.getTag()).onLevelChanged(); 293 } 294 295 @Override getMetricsCategory()296 public int getMetricsCategory() { 297 return MetricsProto.MetricsEvent.SETTINGS_NETWORK_CATEGORY; 298 } 299 } 300