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