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.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; 20 import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION; 21 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.net.wifi.WifiConfiguration; 27 import android.net.wifi.WifiManager; 28 import android.os.Bundle; 29 import android.os.UserManager; 30 import android.support.annotation.VisibleForTesting; 31 import android.util.Log; 32 33 import com.android.internal.logging.nano.MetricsProto; 34 import com.android.settings.R; 35 import com.android.settings.SettingsActivity; 36 import com.android.settings.dashboard.RestrictedDashboardFragment; 37 import com.android.settings.widget.SwitchBar; 38 import com.android.settings.widget.SwitchBarController; 39 import com.android.settingslib.core.AbstractPreferenceController; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 public class WifiTetherSettings extends RestrictedDashboardFragment 45 implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener { 46 47 private static final String TAG = "WifiTetherSettings"; 48 private static final IntentFilter TETHER_STATE_CHANGE_FILTER; 49 private static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off"; 50 51 private WifiTetherSwitchBarController mSwitchBarController; 52 private WifiTetherSSIDPreferenceController mSSIDPreferenceController; 53 private WifiTetherPasswordPreferenceController mPasswordPreferenceController; 54 private WifiTetherApBandPreferenceController mApBandPreferenceController; 55 private WifiTetherSecurityPreferenceController mSecurityPreferenceController; 56 57 private WifiManager mWifiManager; 58 private boolean mRestartWifiApAfterConfigChange; 59 60 @VisibleForTesting 61 TetherChangeReceiver mTetherChangeReceiver; 62 63 static { 64 TETHER_STATE_CHANGE_FILTER = new IntentFilter(ACTION_TETHER_STATE_CHANGED); 65 TETHER_STATE_CHANGE_FILTER.addAction(WIFI_AP_STATE_CHANGED_ACTION); 66 } 67 68 public WifiTetherSettings() { 69 super(UserManager.DISALLOW_CONFIG_TETHERING); 70 } 71 72 @Override 73 public int getMetricsCategory() { 74 return MetricsProto.MetricsEvent.WIFI_TETHER_SETTINGS; 75 } 76 77 @Override 78 protected String getLogTag() { 79 return "WifiTetherSettings"; 80 } 81 82 @Override 83 public void onAttach(Context context) { 84 super.onAttach(context); 85 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 86 mTetherChangeReceiver = new TetherChangeReceiver(); 87 } 88 89 @Override 90 public void onActivityCreated(Bundle savedInstanceState) { 91 super.onActivityCreated(savedInstanceState); 92 // Assume we are in a SettingsActivity. This is only safe because we currently use 93 // SettingsActivity as base for all preference fragments. 94 final SettingsActivity activity = (SettingsActivity) getActivity(); 95 final SwitchBar switchBar = activity.getSwitchBar(); 96 mSwitchBarController = new WifiTetherSwitchBarController(activity, 97 new SwitchBarController(switchBar)); 98 getLifecycle().addObserver(mSwitchBarController); 99 switchBar.show(); 100 } 101 102 @Override 103 public void onStart() { 104 super.onStart(); 105 final Context context = getContext(); 106 if (context != null) { 107 context.registerReceiver(mTetherChangeReceiver, TETHER_STATE_CHANGE_FILTER); 108 } 109 } 110 111 @Override 112 public void onStop() { 113 super.onStop(); 114 final Context context = getContext(); 115 if (context != null) { 116 context.unregisterReceiver(mTetherChangeReceiver); 117 } 118 } 119 120 121 @Override 122 protected int getPreferenceScreenResId() { 123 return R.xml.wifi_tether_settings; 124 } 125 126 @Override 127 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 128 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 129 mSSIDPreferenceController = new WifiTetherSSIDPreferenceController(context, this); 130 mSecurityPreferenceController = new WifiTetherSecurityPreferenceController(context, this); 131 mPasswordPreferenceController = new WifiTetherPasswordPreferenceController(context, this); 132 mApBandPreferenceController = new WifiTetherApBandPreferenceController(context, this); 133 134 controllers.add(mSSIDPreferenceController); 135 controllers.add(mSecurityPreferenceController); 136 controllers.add(mPasswordPreferenceController); 137 controllers.add(mApBandPreferenceController); 138 controllers.add( 139 new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF)); 140 return controllers; 141 } 142 143 @Override 144 public void onTetherConfigUpdated() { 145 final WifiConfiguration config = buildNewConfig(); 146 mPasswordPreferenceController.updateVisibility(config.getAuthType()); 147 148 /** 149 * if soft AP is stopped, bring up 150 * else restart with new config 151 * TODO: update config on a running access point when framework support is added 152 */ 153 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) { 154 Log.d("TetheringSettings", 155 "Wifi AP config changed while enabled, stop and restart"); 156 mRestartWifiApAfterConfigChange = true; 157 mSwitchBarController.stopTether(); 158 } 159 mWifiManager.setWifiApConfiguration(config); 160 } 161 162 private WifiConfiguration buildNewConfig() { 163 final WifiConfiguration config = new WifiConfiguration(); 164 final int securityType = mSecurityPreferenceController.getSecurityType(); 165 166 config.SSID = mSSIDPreferenceController.getSSID(); 167 config.allowedKeyManagement.set(securityType); 168 config.preSharedKey = mPasswordPreferenceController.getPasswordValidated(securityType); 169 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 170 config.apBand = mApBandPreferenceController.getBandIndex(); 171 return config; 172 } 173 174 private void startTether() { 175 mRestartWifiApAfterConfigChange = false; 176 mSwitchBarController.startTether(); 177 } 178 179 private void updateDisplayWithNewConfig() { 180 use(WifiTetherSSIDPreferenceController.class) 181 .updateDisplay(); 182 use(WifiTetherSecurityPreferenceController.class) 183 .updateDisplay(); 184 use(WifiTetherPasswordPreferenceController.class) 185 .updateDisplay(); 186 use(WifiTetherApBandPreferenceController.class) 187 .updateDisplay(); 188 } 189 190 @VisibleForTesting 191 class TetherChangeReceiver extends BroadcastReceiver { 192 @Override 193 public void onReceive(Context content, Intent intent) { 194 String action = intent.getAction(); 195 Log.d(TAG, "updating display config due to receiving broadcast action " + action); 196 updateDisplayWithNewConfig(); 197 if (action.equals(ACTION_TETHER_STATE_CHANGED)) { 198 if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED 199 && mRestartWifiApAfterConfigChange) { 200 startTether(); 201 } 202 } else if (action.equals(WIFI_AP_STATE_CHANGED_ACTION)) { 203 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0); 204 if (state == WifiManager.WIFI_AP_STATE_DISABLED 205 && mRestartWifiApAfterConfigChange) { 206 startTether(); 207 } 208 } 209 } 210 } 211 } 212