blob: 1c7ea1d5ce146420c822d10d83198b1fcc713534 [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
Zhen Zhang02dfed62020-01-13 14:57:23 -080023import static com.android.settings.network.WifiTetherDisablePreferenceController.KEY_ENABLE_WIFI_TETHERING;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080024
25import android.app.settings.SettingsEnums;
Zhen Zhang02dfed62020-01-13 14:57:23 -080026import android.bluetooth.BluetoothAdapter;
27import android.bluetooth.BluetoothPan;
28import android.bluetooth.BluetoothProfile;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080029import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.SharedPreferences;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080034import android.net.wifi.SoftApConfiguration;
35import android.net.wifi.WifiManager;
36import android.os.Bundle;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080037import android.os.UserManager;
38import android.text.TextUtils;
39import android.util.Log;
40
41import androidx.annotation.VisibleForTesting;
42import androidx.preference.Preference;
43import androidx.preference.PreferenceGroup;
44
45import com.android.settings.dashboard.RestrictedDashboardFragment;
46import com.android.settings.datausage.DataSaverBackend;
47import com.android.settings.network.TetherEnabler;
48import com.android.settings.search.BaseSearchIndexProvider;
Zhen Zhang02dfed62020-01-13 14:57:23 -080049import com.android.settings.widget.SwitchBar;
50import com.android.settings.widget.SwitchBarController;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080051import com.android.settings.wifi.tether.WifiTetherApBandPreferenceController;
52import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController;
53import com.android.settings.wifi.tether.WifiTetherBasePreferenceController;
54import com.android.settings.wifi.tether.WifiTetherPasswordPreferenceController;
55import com.android.settings.wifi.tether.WifiTetherSSIDPreferenceController;
56import com.android.settings.wifi.tether.WifiTetherSecurityPreferenceController;
57import com.android.settingslib.TetherUtil;
58import com.android.settingslib.core.AbstractPreferenceController;
59import com.android.settingslib.search.SearchIndexable;
60
61import java.util.ArrayList;
62import java.util.List;
Zhen Zhang02dfed62020-01-13 14:57:23 -080063import java.util.concurrent.atomic.AtomicReference;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080064
65/**
Zhen Zhang02dfed62020-01-13 14:57:23 -080066 * Displays preferences for all Tethering options.
Zhen Zhangb60e8ca2020-01-07 18:14:30 -080067 * TODO(b/147323306): Add tether option preferences into this fragment after controllers created.
68 */
69@SearchIndexable
70public final class AllInOneTetherSettings extends RestrictedDashboardFragment
71 implements DataSaverBackend.Listener,
72 WifiTetherBasePreferenceController.OnTetherConfigUpdateListener,
73 SharedPreferences.OnSharedPreferenceChangeListener {
74
75 @VisibleForTesting
76 static final String KEY_TETHER_PREFS_SCREEN = "tether_prefs_screen";
77 @VisibleForTesting
78 static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
79 @VisibleForTesting
80 static final String KEY_WIFI_TETHER_NETWORK_PASSWORD = "wifi_tether_network_password";
81 @VisibleForTesting
82 static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
83 @VisibleForTesting
84 static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
85
86 private static final String KEY_WIFI_TETHER_GROUP = "wifi_tether_settings_group";
87 private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver";
88 private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 2;
89 private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3;
90 private static final String TAG = "AllInOneTetherSettings";
91
92 private boolean mUnavailable;
93
94 private DataSaverBackend mDataSaverBackend;
95 private boolean mDataSaverEnabled;
96 private Preference mDataSaverFooter;
97
98 private WifiManager mWifiManager;
99 private boolean mRestartWifiApAfterConfigChange;
Zhen Zhang02dfed62020-01-13 14:57:23 -0800100 private final AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<>();
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800101
102 private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
103 private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
104 private WifiTetherApBandPreferenceController mApBandPreferenceController;
105 private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
106 private PreferenceGroup mWifiTetherGroup;
107 private SharedPreferences mSharedPreferences;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800108 private boolean mWifiTetherChosen;
Zhen Zhang02dfed62020-01-13 14:57:23 -0800109 private TetherEnabler mTetherEnabler;
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800110
111 private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() {
112 @Override
113 public void onReceive(Context content, Intent intent) {
114 String action = intent.getAction();
115 if (Log.isLoggable(TAG, Log.DEBUG)) {
116 Log.d(TAG, "updating display config due to receiving broadcast action " + action);
117 }
118 updateDisplayWithNewConfig();
119 if (TextUtils.equals(action, ACTION_TETHER_STATE_CHANGED)) {
120 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
121 && mRestartWifiApAfterConfigChange) {
122 mRestartWifiApAfterConfigChange = false;
Zhen Zhang02dfed62020-01-13 14:57:23 -0800123 mTetherEnabler.startTethering(TETHERING_WIFI);
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800124 }
125 } else if (TextUtils.equals(action, WIFI_AP_STATE_CHANGED_ACTION)) {
126 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
127 if (state == WifiManager.WIFI_AP_STATE_DISABLED
128 && mRestartWifiApAfterConfigChange) {
129 mRestartWifiApAfterConfigChange = false;
Zhen Zhang02dfed62020-01-13 14:57:23 -0800130 mTetherEnabler.startTethering(TETHERING_WIFI);
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800131 }
132 }
133 }
134 };
135
Zhen Zhang02dfed62020-01-13 14:57:23 -0800136 private final BluetoothProfile.ServiceListener mProfileServiceListener =
137 new BluetoothProfile.ServiceListener() {
138 public void onServiceConnected(int profile, BluetoothProfile proxy) {
139 mBluetoothPan.set((BluetoothPan) proxy);
140 }
141
142 public void onServiceDisconnected(int profile) {
143 mBluetoothPan.set(null);
144 }
145 };
146
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800147 @Override
148 public int getMetricsCategory() {
149 return SettingsEnums.TETHER;
150 }
151
152 public AllInOneTetherSettings() {
153 super(UserManager.DISALLOW_CONFIG_TETHERING);
154 }
155
156 @Override
157 public void onAttach(Context context) {
158 super.onAttach(context);
159 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800160 mSharedPreferences =
161 context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE);
162
163 mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
164 mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
165 mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
166 mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class);
167 }
168
169 @Override
170 public void onCreate(Bundle icicle) {
171 super.onCreate(icicle);
172
173 mDataSaverBackend = new DataSaverBackend(getContext());
174 mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
175 mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER);
176 mWifiTetherGroup = findPreference(KEY_WIFI_TETHER_GROUP);
177
178 setIfOnlyAvailableForAdmins(true);
179 if (isUiRestricted()) {
180 mUnavailable = true;
181 return;
182 }
183
184 mDataSaverBackend.addListener(this);
185
186 // Set initial state based on Data Saver mode.
187 onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled());
188
189 // Set initial state based on SharedPreferences value.
190 onSharedPreferenceChanged(mSharedPreferences, KEY_ENABLE_WIFI_TETHERING);
191
192 // TODO(b/147325229): Hide advanced settings like security and ap band.
193 }
194
195 @Override
Zhen Zhang02dfed62020-01-13 14:57:23 -0800196 public void onActivityCreated(Bundle savedInstanceState) {
197 super.onActivityCreated(savedInstanceState);
198 if (mUnavailable) {
199 return;
200 }
201 // Assume we are in a SettingsActivity. This is only safe because we currently use
202 // SettingsActivity as base for all preference fragments.
203 final SettingsActivity activity = (SettingsActivity) getActivity();
Zhen Zhang0ccc8492020-01-17 15:23:40 -0800204 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
Zhen Zhang02dfed62020-01-13 14:57:23 -0800205 if (adapter != null) {
206 adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener,
207 BluetoothProfile.PAN);
208 }
209 final SwitchBar switchBar = activity.getSwitchBar();
210 mTetherEnabler = new TetherEnabler(activity,
211 new SwitchBarController(switchBar), mBluetoothPan);
212 getSettingsLifecycle().addObserver(mTetherEnabler);
213 switchBar.show();
214 }
215
216 @Override
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800217 public void onStart() {
218 super.onStart();
219
220 if (mUnavailable) {
221 if (!isUiRestrictedByOnlyAdmin()) {
222 getEmptyTextView().setText(R.string.tethering_settings_not_available);
223 }
224 getPreferenceScreen().removeAll();
225 return;
226 }
227 final Context context = getContext();
228 if (context != null) {
229 IntentFilter filter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
230 filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
231 context.registerReceiver(mTetherChangeReceiver, filter);
232 }
233 }
234
235 @Override
236 public void onResume() {
237 super.onResume();
238 mSharedPreferences.registerOnSharedPreferenceChangeListener(this);
239 }
240
241 @Override
242 public void onPause() {
243 super.onPause();
244 mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
245 }
246
247 @Override
248 public void onStop() {
249 super.onStop();
250 final Context context = getContext();
251 if (context != null) {
252 context.unregisterReceiver(mTetherChangeReceiver);
253 }
254 }
255
256 @Override
257 public void onDestroy() {
258 mDataSaverBackend.remListener(this);
259 super.onDestroy();
260 }
261
262 @Override
263 public void onDataSaverChanged(boolean isDataSaving) {
264 mDataSaverEnabled = isDataSaving;
265 mDataSaverFooter.setVisible(mDataSaverEnabled);
266 }
267
268 @Override
269 public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) {
270 // Do nothing
271 }
272
273 @Override
274 public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) {
275 // Do nothing
276 }
277
278 @Override
279 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
280 return buildPreferenceControllers(context, this);
281 }
282
283 private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
284 WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
285 final List<AbstractPreferenceController> controllers = new ArrayList<>();
286 controllers.add(
287 new WifiTetherSSIDPreferenceController(context, listener));
288 controllers.add(
289 new WifiTetherPasswordPreferenceController(context, listener));
290 controllers.add(
291 new WifiTetherApBandPreferenceController(context, listener));
292 controllers.add(
293 new WifiTetherSecurityPreferenceController(context, listener));
294 controllers.add(
295 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
296
297 return controllers;
298 }
299
300 @Override
301 protected int getPreferenceScreenResId() {
302 return R.xml.all_tether_prefs;
303 }
304
305 @Override
306 protected String getLogTag() {
307 return TAG;
308 }
309
310 @Override
311 public void onExpandButtonClick() {
312 super.onExpandButtonClick();
313 // TODO(b/147325229): Display hidden advanced settings like security and ap band.
314 }
315
316 @Override
317 public int getHelpResource() {
318 return R.string.help_url_tether;
319 }
320
321 @Override
322 public void onTetherConfigUpdated(AbstractPreferenceController controller) {
323 final SoftApConfiguration config = buildNewConfig();
324 mPasswordPreferenceController.updateVisibility(config.getSecurityType());
325 mWifiManager.setSoftApConfiguration(config);
326
327 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
328 if (Log.isLoggable(TAG, Log.DEBUG)) {
329 Log.d(TAG, "Wifi AP config changed while enabled, stop and restart");
330 }
331 mRestartWifiApAfterConfigChange = true;
Zhen Zhang02dfed62020-01-13 14:57:23 -0800332 mTetherEnabler.stopTethering(TETHERING_WIFI);
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800333 }
334
335 if (controller instanceof WifiTetherSecurityPreferenceController) {
336 reConfigInitialExpandedChildCount();
337 }
338 }
339
340 private SoftApConfiguration buildNewConfig() {
341 final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
342 final int securityType = mSecurityPreferenceController.getSecurityType();
343 configBuilder.setSsid(mSSIDPreferenceController.getSSID());
344 if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
345 configBuilder.setPassphrase(
346 mPasswordPreferenceController.getPasswordValidated(securityType),
347 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
348 }
349 configBuilder.setBand(mApBandPreferenceController.getBandIndex());
350 return configBuilder.build();
351 }
352
353 private void updateDisplayWithNewConfig() {
354 mSSIDPreferenceController.updateDisplay();
355 mSecurityPreferenceController.updateDisplay();
356 mPasswordPreferenceController.updateDisplay();
357 mApBandPreferenceController.updateDisplay();
358 }
359
360 @Override
361 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
362 if (TextUtils.equals(key, KEY_ENABLE_WIFI_TETHERING)) {
363 mWifiTetherChosen = sharedPreferences.getBoolean(KEY_ENABLE_WIFI_TETHERING, true);
364 mWifiTetherGroup.setVisible(mWifiTetherChosen);
365 reConfigInitialExpandedChildCount();
366 }
367 }
368
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800369 private void reConfigInitialExpandedChildCount() {
370 getPreferenceScreen().setInitialExpandedChildrenCount(getInitialExpandedChildCount());
371 }
372
373 @Override
374 public int getInitialExpandedChildCount() {
375 if (!mWifiTetherChosen) {
376 // Expand all preferences in the screen.
377 return getPreferenceScreen().getPreferenceCount();
378 }
379
380 if (mSecurityPreferenceController == null) {
381 return EXPANDED_CHILD_COUNT_DEFAULT;
382 }
383
384 return (mSecurityPreferenceController.getSecurityType()
385 == SoftApConfiguration.SECURITY_TYPE_OPEN)
386 ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT;
387 }
388
389 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
390 new BaseSearchIndexProvider(R.xml.all_tether_prefs) {
391
392 @Override
393 public List<String> getNonIndexableKeys(Context context) {
394 final List<String> keys = super.getNonIndexableKeys(context);
395
396 if (!TetherUtil.isTetherAvailable(context)) {
397 keys.add(KEY_TETHER_PREFS_SCREEN);
398 keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
399 keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
400 keys.add(KEY_WIFI_TETHER_AUTO_OFF);
401 keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
402 }
403
404 return keys;
405 }
406
407 @Override
Zhen Zhang0ccc8492020-01-17 15:23:40 -0800408 protected boolean isPageSearchEnabled(Context context) {
409 return context.getResources().getBoolean(
410 R.bool.config_show_all_in_one_tether_settings);
411 }
412
413 @Override
Zhen Zhangb60e8ca2020-01-07 18:14:30 -0800414 public List<AbstractPreferenceController> createPreferenceControllers(
415 Context context) {
416 return buildPreferenceControllers(context, null /* AllTetherSettings */);
417 }
418 };
419}