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