• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.settings.wifi.tether;
18 
19 import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
20 import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
21 
22 import android.app.settings.SettingsEnums;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.wifi.SoftApConfiguration;
28 import android.net.wifi.WifiManager;
29 import android.os.Bundle;
30 import android.os.UserManager;
31 import android.util.FeatureFlagUtils;
32 import android.util.Log;
33 
34 import androidx.annotation.VisibleForTesting;
35 import androidx.preference.PreferenceGroup;
36 
37 import com.android.settings.R;
38 import com.android.settings.SettingsActivity;
39 import com.android.settings.core.FeatureFlags;
40 import com.android.settings.dashboard.RestrictedDashboardFragment;
41 import com.android.settings.search.BaseSearchIndexProvider;
42 import com.android.settings.widget.SettingsMainSwitchBar;
43 import com.android.settingslib.TetherUtil;
44 import com.android.settingslib.core.AbstractPreferenceController;
45 import com.android.settingslib.search.SearchIndexable;
46 
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 @SearchIndexable
51 public class WifiTetherSettings extends RestrictedDashboardFragment
52         implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener {
53 
54     private static final String TAG = "WifiTetherSettings";
55     private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
56     private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
57     private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3;
58 
59     @VisibleForTesting
60     static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
61     @VisibleForTesting
62     static final String KEY_WIFI_TETHER_NETWORK_PASSWORD = "wifi_tether_network_password";
63     @VisibleForTesting
64     static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
65     @VisibleForTesting
66     static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
67             WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
68 
69     private WifiTetherSwitchBarController mSwitchBarController;
70     private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
71     private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
72     private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
73     private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
74 
75     private WifiManager mWifiManager;
76     private boolean mRestartWifiApAfterConfigChange;
77     private boolean mUnavailable;
78 
79     @VisibleForTesting
80     TetherChangeReceiver mTetherChangeReceiver;
81 
82     static {
83         TETHER_STATE_CHANGE_FILTER = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
84         TETHER_STATE_CHANGE_FILTER.addAction(WIFI_AP_STATE_CHANGED_ACTION);
85     }
86 
WifiTetherSettings()87     public WifiTetherSettings() {
88         super(UserManager.DISALLOW_CONFIG_TETHERING);
89     }
90 
91     @Override
getMetricsCategory()92     public int getMetricsCategory() {
93         return SettingsEnums.WIFI_TETHER_SETTINGS;
94     }
95 
96     @Override
getLogTag()97     protected String getLogTag() {
98         return "WifiTetherSettings";
99     }
100 
101     @Override
onCreate(Bundle icicle)102     public void onCreate(Bundle icicle) {
103         super.onCreate(icicle);
104         setIfOnlyAvailableForAdmins(true);
105         if (isUiRestricted()) {
106             mUnavailable = true;
107         }
108     }
109 
110     @Override
onAttach(Context context)111     public void onAttach(Context context) {
112         super.onAttach(context);
113         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
114         mTetherChangeReceiver = new TetherChangeReceiver();
115 
116         mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
117         mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
118         mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
119         mMaxCompatibilityPrefController =
120                 use(WifiTetherMaximizeCompatibilityPreferenceController.class);
121     }
122 
123     @Override
onActivityCreated(Bundle savedInstanceState)124     public void onActivityCreated(Bundle savedInstanceState) {
125         super.onActivityCreated(savedInstanceState);
126         if (mUnavailable) {
127             return;
128         }
129         // Assume we are in a SettingsActivity. This is only safe because we currently use
130         // SettingsActivity as base for all preference fragments.
131         final SettingsActivity activity = (SettingsActivity) getActivity();
132         final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
133         switchBar.setTitle(getContext().getString(R.string.use_wifi_hotsopt_main_switch_title));
134         mSwitchBarController = new WifiTetherSwitchBarController(activity, switchBar);
135         getSettingsLifecycle().addObserver(mSwitchBarController);
136         switchBar.show();
137     }
138 
139     @Override
onStart()140     public void onStart() {
141         super.onStart();
142         if (mUnavailable) {
143             if (!isUiRestrictedByOnlyAdmin()) {
144                 getEmptyTextView().setText(R.string.tethering_settings_not_available);
145             }
146             getPreferenceScreen().removeAll();
147             return;
148         }
149         final Context context = getContext();
150         if (context != null) {
151             context.registerReceiver(mTetherChangeReceiver, TETHER_STATE_CHANGE_FILTER);
152         }
153     }
154 
155     @Override
onStop()156     public void onStop() {
157         super.onStop();
158         if (mUnavailable) {
159             return;
160         }
161         final Context context = getContext();
162         if (context != null) {
163             context.unregisterReceiver(mTetherChangeReceiver);
164         }
165     }
166 
167 
168     @Override
getPreferenceScreenResId()169     protected int getPreferenceScreenResId() {
170         return R.xml.wifi_tether_settings;
171     }
172 
173     @Override
createPreferenceControllers(Context context)174     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
175         return buildPreferenceControllers(context, this::onTetherConfigUpdated);
176     }
177 
buildPreferenceControllers(Context context, WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener)178     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
179             WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
180         final List<AbstractPreferenceController> controllers = new ArrayList<>();
181         controllers.add(new WifiTetherSSIDPreferenceController(context, listener));
182         controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
183         controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
184         controllers.add(
185                 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
186         controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener));
187         return controllers;
188     }
189 
190     @Override
onTetherConfigUpdated(AbstractPreferenceController context)191     public void onTetherConfigUpdated(AbstractPreferenceController context) {
192         final SoftApConfiguration config = buildNewConfig();
193         mPasswordPreferenceController.setSecurityType(config.getSecurityType());
194 
195         /**
196          * if soft AP is stopped, bring up
197          * else restart with new config
198          * TODO: update config on a running access point when framework support is added
199          */
200         if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
201             Log.d("TetheringSettings",
202                     "Wifi AP config changed while enabled, stop and restart");
203             mRestartWifiApAfterConfigChange = true;
204             mSwitchBarController.stopTether();
205         }
206         mWifiManager.setSoftApConfiguration(config);
207 
208         if (context instanceof WifiTetherSecurityPreferenceController) {
209             reConfigInitialExpandedChildCount();
210         }
211     }
212 
buildNewConfig()213     private SoftApConfiguration buildNewConfig() {
214         final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
215         final int securityType = mSecurityPreferenceController.getSecurityType();
216         configBuilder.setSsid(mSSIDPreferenceController.getSSID());
217         if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) {
218             configBuilder.setPassphrase(
219                     mPasswordPreferenceController.getPasswordValidated(securityType),
220                     securityType);
221         }
222         mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder);
223         return configBuilder.build();
224     }
225 
startTether()226     private void startTether() {
227         mRestartWifiApAfterConfigChange = false;
228         mSwitchBarController.startTether();
229     }
230 
updateDisplayWithNewConfig()231     private void updateDisplayWithNewConfig() {
232         use(WifiTetherSSIDPreferenceController.class).updateDisplay();
233         use(WifiTetherSecurityPreferenceController.class).updateDisplay();
234         use(WifiTetherPasswordPreferenceController.class).updateDisplay();
235         use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay();
236     }
237 
238     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
239             new BaseSearchIndexProvider(R.xml.wifi_tether_settings) {
240 
241                 @Override
242                 public List<String> getNonIndexableKeys(Context context) {
243                     final List<String> keys = super.getNonIndexableKeys(context);
244 
245                     if (!TetherUtil.isTetherAvailable(context)) {
246                         keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
247                         keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
248                         keys.add(KEY_WIFI_TETHER_AUTO_OFF);
249                         keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
250                     }
251 
252                     // Remove duplicate
253                     keys.add(KEY_WIFI_TETHER_SCREEN);
254                     return keys;
255                 }
256 
257                 @Override
258                 protected boolean isPageSearchEnabled(Context context) {
259                     return !FeatureFlagUtils.isEnabled(context, FeatureFlags.TETHER_ALL_IN_ONE);
260                 }
261 
262                 @Override
263                 public List<AbstractPreferenceController> createPreferenceControllers(
264                         Context context) {
265                     return buildPreferenceControllers(context, null /* listener */);
266                 }
267             };
268 
269     @VisibleForTesting
270     class TetherChangeReceiver extends BroadcastReceiver {
271         @Override
onReceive(Context content, Intent intent)272         public void onReceive(Context content, Intent intent) {
273             String action = intent.getAction();
274             Log.d(TAG, "updating display config due to receiving broadcast action " + action);
275             updateDisplayWithNewConfig();
276             if (action.equals(ACTION_TETHER_STATE_CHANGED)) {
277                 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
278                         && mRestartWifiApAfterConfigChange) {
279                     startTether();
280                 }
281             } else if (action.equals(WIFI_AP_STATE_CHANGED_ACTION)) {
282                 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
283                 if (state == WifiManager.WIFI_AP_STATE_DISABLED
284                         && mRestartWifiApAfterConfigChange) {
285                     startTether();
286                 }
287             }
288         }
289     }
290 
reConfigInitialExpandedChildCount()291     private void reConfigInitialExpandedChildCount() {
292         final PreferenceGroup screen = getPreferenceScreen();
293         if (screen != null) {
294             screen.setInitialExpandedChildrenCount(getInitialExpandedChildCount());
295         }
296     }
297 }
298