blob: d6366b21280100f2593343bc07b4896c2df1dd0c [file] [log] [blame]
Zhen Zhangb60e8ca2020-01-07 18:14:30 -08001/*
2 * Copyright (C) 2020 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
17package com.android.settings;
18
19import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
20import static android.net.ConnectivityManager.TETHERING_WIFI;
21import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
22
23import static com.android.settings.network.WifiTetherDisablePreferenceController
24 .KEY_ENABLE_WIFI_TETHERING;
25
26import android.app.settings.SettingsEnums;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.SharedPreferences;
32import android.net.ConnectivityManager;
33import android.net.wifi.SoftApConfiguration;
34import android.net.wifi.WifiManager;
35import android.os.Bundle;
36import android.os.Handler;
37import android.os.Looper;
38import android.os.UserManager;
39import android.text.TextUtils;
40import android.util.Log;
41
42import androidx.annotation.VisibleForTesting;
43import androidx.preference.Preference;
44import androidx.preference.PreferenceGroup;
45
46import com.android.settings.dashboard.RestrictedDashboardFragment;
47import com.android.settings.datausage.DataSaverBackend;
48import com.android.settings.network.TetherEnabler;
49import com.android.settings.search.BaseSearchIndexProvider;
50import com.android.settings.wifi.tether.WifiTetherApBandPreferenceController;
51import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController;
52import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
53import com.android.settings.wifi.tether.WifiTetherPasswordPreferenceController;
54import com.android.settings.wifi.tether.WifiTetherSSIDPreferenceController;
55import com.android.settings.wifi.tether.WifiTetherSecurityPreferenceController;
56import com.android.settingslib.TetherUtil;
57import com.android.settingslib.core.AbstractPreferenceController;
58import com.android.settingslib.search.SearchIndexable;
59
60import java.util.ArrayList;
61import java.util.List;
62
63/**
64 * Displays preferences for Tethering.
65 * TODO(b/147322704): Use TetherEnabler in this fragment to manage tethering switch on/off.
66 * TODO(b/147323306): Add tether option preferences into this fragment after controllers created.
67 */
68@SearchIndexable
69public final class AllInOneTetherSettings extends RestrictedDashboardFragment
70 implements DataSaverBackend.Listener,
71 WifiTetherBasePreferenceController.OnTetherConfigUpdateListener,
72 SharedPreferences.OnSharedPreferenceChangeListener {
73
74 @VisibleForTesting
75 static final String KEY_TETHER_PREFS_SCREEN = "tether_prefs_screen";
76 @VisibleForTesting
77 static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
78 @VisibleForTesting
79 static final String KEY_WIFI_TETHER_NETWORK_PASSWORD = "wifi_tether_network_password";
80 @VisibleForTesting
81 static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
82 @VisibleForTesting
83 static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
84
85 private static final String KEY_WIFI_TETHER_GROUP = "wifi_tether_settings_group";
86 private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver";
87 private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 2;
88 private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3;
89 private static final String TAG = "AllInOneTetherSettings";
90
91 private boolean mUnavailable;
92
93 private DataSaverBackend mDataSaverBackend;
94 private boolean mDataSaverEnabled;
95 private Preference mDataSaverFooter;
96
97 private WifiManager mWifiManager;
98 private boolean mRestartWifiApAfterConfigChange;
99
100 private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
101 private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
102 private WifiTetherApBandPreferenceController mApBandPreferenceController;
103 private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
104 private PreferenceGroup mWifiTetherGroup;
105 private SharedPreferences mSharedPreferences;
106 private ConnectivityManager mConnectivityManager;
107 private boolean mWifiTetherChosen;
108
109 private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
110 @Override
111 public void onReceive(Context content, Intent intent) {
112 String action = intent.getAction();
113 if (Log.isLoggable(TAG, Log.DEBUG)) {
114 Log.d(TAG, "updating display config due to receiving broadcast action " + action);
115 }
116 updateDisplayWithNewConfig();
117 if (TextUtils.equals(action, ACTION_TETHER_STATE_CHANGED)) {
118 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
119 && mRestartWifiApAfterConfigChange) {
120 mRestartWifiApAfterConfigChange = false;
121 startTether();
122 }
123 } else if (TextUtils.equals(action, WIFI_AP_STATE_CHANGED_ACTION)) {
124 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
125 if (state == WifiManager.WIFI_AP_STATE_DISABLED
126 && mRestartWifiApAfterConfigChange) {
127 mRestartWifiApAfterConfigChange = false;
128 startTether();
129 }
130 }
131 }
132 };
133
134 @Override
135 public int getMetricsCategory() {
136 return SettingsEnums.TETHER;
137 }
138
139 public AllInOneTetherSettings() {
140 super(UserManager.DISALLOW_CONFIG_TETHERING);
141 }
142
143 @Override
144 public void onAttach(Context context) {
145 super.onAttach(context);
146 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
147 mConnectivityManager =
148 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
149 mSharedPreferences =
150 context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE);
151
152 mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
153 mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
154 mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
155 mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class);
156 }
157
158 @Override
159 public void onCreate(Bundle icicle) {
160 super.onCreate(icicle);
161
162 mDataSaverBackend = new DataSaverBackend(getContext());
163 mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
164 mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER);
165 mWifiTetherGroup = findPreference(KEY_WIFI_TETHER_GROUP);
166
167 setIfOnlyAvailableForAdmins(true);
168 if (isUiRestricted()) {
169 mUnavailable = true;
170 return;
171 }
172
173 mDataSaverBackend.addListener(this);
174
175 // Set initial state based on Data Saver mode.
176 onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled());
177
178 // Set initial state based on SharedPreferences value.
179 onSharedPreferenceChanged(mSharedPreferences, KEY_ENABLE_WIFI_TETHERING);
180
181 // TODO(b/147325229): Hide advanced settings like security and ap band.
182 }
183
184 @Override
185 public void onStart() {
186 super.onStart();
187
188 if (mUnavailable) {
189 if (!isUiRestrictedByOnlyAdmin()) {
190 getEmptyTextView().setText(R.string.tethering_settings_not_available);
191 }
192 getPreferenceScreen().removeAll();
193 return;
194 }
195 final Context context = getContext();
196 if (context != null) {
197 IntentFilter filter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
198 filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
199 context.registerReceiver(mTetherChangeReceiver, filter);
200 }
201 }
202
203 @Override
204 public void onResume() {
205 super.onResume();
206 mSharedPreferences.registerOnSharedPreferenceChangeListener(this);
207 }
208
209 @Override
210 public void onPause() {
211 super.onPause();
212 mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
213 }
214
215 @Override
216 public void onStop() {
217 super.onStop();
218 final Context context = getContext();
219 if (context != null) {
220 context.unregisterReceiver(mTetherChangeReceiver);
221 }
222 }
223
224 @Override
225 public void onDestroy() {
226 mDataSaverBackend.remListener(this);
227 super.onDestroy();
228 }
229
230 @Override
231 public void onDataSaverChanged(boolean isDataSaving) {
232 mDataSaverEnabled = isDataSaving;
233 mDataSaverFooter.setVisible(mDataSaverEnabled);
234 }
235
236 @Override
237 public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) {
238 // Do nothing
239 }
240
241 @Override
242 public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) {
243 // Do nothing
244 }
245
246 @Override
247 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
248 return buildPreferenceControllers(context, this);
249 }
250
251 private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
252 WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
253 final List<AbstractPreferenceController> controllers = new ArrayList<>();
254 controllers.add(
255 new WifiTetherSSIDPreferenceController(context, listener));
256 controllers.add(
257 new WifiTetherPasswordPreferenceController(context, listener));
258 controllers.add(
259 new WifiTetherApBandPreferenceController(context, listener));
260 controllers.add(
261 new WifiTetherSecurityPreferenceController(context, listener));
262 controllers.add(
263 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
264
265 return controllers;
266 }
267
268 @Override
269 protected int getPreferenceScreenResId() {
270 return R.xml.all_tether_prefs;
271 }
272
273 @Override
274 protected String getLogTag() {
275 return TAG;
276 }
277
278 @Override
279 public void onExpandButtonClick() {
280 super.onExpandButtonClick();
281 // TODO(b/147325229): Display hidden advanced settings like security and ap band.
282 }
283
284 @Override
285 public int getHelpResource() {
286 return R.string.help_url_tether;
287 }
288
289 @Override
290 public void onTetherConfigUpdated(AbstractPreferenceController controller) {
291 final SoftApConfiguration config = buildNewConfig();
292 mPasswordPreferenceController.updateVisibility(config.getSecurityType());
293 mWifiManager.setSoftApConfiguration(config);
294
295 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
296 if (Log.isLoggable(TAG, Log.DEBUG)) {
297 Log.d(TAG, "Wifi AP config changed while enabled, stop and restart");
298 }
299 mRestartWifiApAfterConfigChange = true;
300 // TODO(b/147322704): Use TethetEnabler to stop tethering.
301 mConnectivityManager.stopTethering(TETHERING_WIFI);
302 }
303
304 if (controller instanceof WifiTetherSecurityPreferenceController) {
305 reConfigInitialExpandedChildCount();
306 }
307 }
308
309 private SoftApConfiguration buildNewConfig() {
310 final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
311 final int securityType = mSecurityPreferenceController.getSecurityType();
312 configBuilder.setSsid(mSSIDPreferenceController.getSSID());
313 if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
314 configBuilder.setPassphrase(
315 mPasswordPreferenceController.getPasswordValidated(securityType),
316 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
317 }
318 configBuilder.setBand(mApBandPreferenceController.getBandIndex());
319 return configBuilder.build();
320 }
321
322 private void updateDisplayWithNewConfig() {
323 mSSIDPreferenceController.updateDisplay();
324 mSecurityPreferenceController.updateDisplay();
325 mPasswordPreferenceController.updateDisplay();
326 mApBandPreferenceController.updateDisplay();
327 }
328
329 @Override
330 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
331 if (TextUtils.equals(key, KEY_ENABLE_WIFI_TETHERING)) {
332 mWifiTetherChosen = sharedPreferences.getBoolean(KEY_ENABLE_WIFI_TETHERING, true);
333 mWifiTetherGroup.setVisible(mWifiTetherChosen);
334 reConfigInitialExpandedChildCount();
335 }
336 }
337
338 private void startTether() {
339 // TODO(b/147322704): Use TetherEnabler to start tethering.
340 if (mWifiManager.isWifiApEnabled()) {
341 return;
342 }
343 mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI,
344 true /*showProvisioningUi*/,
345 new ConnectivityManager.OnStartTetheringCallback() {
346 @Override
347 public void onTetheringFailed() {
348 super.onTetheringFailed();
349 // Do nothing. There is no UI to update at this point.
350 }
351 },
352 new Handler(Looper.getMainLooper()));
353 }
354
355 private void reConfigInitialExpandedChildCount() {
356 getPreferenceScreen().setInitialExpandedChildrenCount(getInitialExpandedChildCount());
357 }
358
359 @Override
360 public int getInitialExpandedChildCount() {
361 if (!mWifiTetherChosen) {
362 // Expand all preferences in the screen.
363 return getPreferenceScreen().getPreferenceCount();
364 }
365
366 if (mSecurityPreferenceController == null) {
367 return EXPANDED_CHILD_COUNT_DEFAULT;
368 }
369
370 return (mSecurityPreferenceController.getSecurityType()
371 == SoftApConfiguration.SECURITY_TYPE_OPEN)
372 ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT;
373 }
374
375 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
376 new BaseSearchIndexProvider(R.xml.all_tether_prefs) {
377
378 @Override
379 public List<String> getNonIndexableKeys(Context context) {
380 final List<String> keys = super.getNonIndexableKeys(context);
381
382 if (!TetherUtil.isTetherAvailable(context)) {
383 keys.add(KEY_TETHER_PREFS_SCREEN);
384 keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
385 keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
386 keys.add(KEY_WIFI_TETHER_AUTO_OFF);
387 keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
388 }
389
390 return keys;
391 }
392
393 @Override
394 public List<AbstractPreferenceController> createPreferenceControllers(
395 Context context) {
396 return buildPreferenceControllers(context, null /* AllTetherSettings */);
397 }
398 };
399}