Files
app_Settings/src/com/android/settings/wifi/WifiEnabler.java
Stephen Chen 19b74d9213 Improve responsiveness of toggling wifi and refactor user restriction logic.
Moved logic for handling wifi state changes into correct listener
method. Changed logic for handling isUiRestricted. This should
streamline toggling flow for WiFi both when Wifi Scanning is on and off,
and in guest mode.

Bug: 36724409
Bug: 36711085
Bug: 36398321

Test: make, test cases in tracking bug
Change-Id: I69fe07369db192c94f81dd678087ac4e8c35197b
2017-03-31 15:47:43 -07:00

224 lines
8.7 KiB
Java

/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils;
import java.util.concurrent.atomic.AtomicBoolean;
public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListener {
private final SwitchWidgetController mSwitchWidget;
private final WifiManager mWifiManager;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private Context mContext;
private boolean mListeningToOnSwitchChange = false;
private AtomicBoolean mConnected = new AtomicBoolean(false);
private boolean mStateMachineEvent;
private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
handleWifiStateChanged(mWifiManager.getWifiState());
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
if (!mConnected.get()) {
handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
}
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mConnected.set(info.isConnected());
handleStateChanged(info.getDetailedState());
}
}
};
private static final String EVENT_DATA_IS_WIFI_ON = "is_wifi_on";
private static final int EVENT_UPDATE_INDEX = 0;
public WifiEnabler(Context context, SwitchWidgetController switchWidget,
MetricsFeatureProvider metricsFeatureProvider) {
mContext = context;
mSwitchWidget = switchWidget;
mSwitchWidget.setListener(this);
mMetricsFeatureProvider = metricsFeatureProvider;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
// The order matters! We really should not depend on this. :(
mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
setupSwitchController();
}
public void setupSwitchController() {
final int state = mWifiManager.getWifiState();
handleWifiStateChanged(state);
if (!mListeningToOnSwitchChange) {
mSwitchWidget.startListening();
mListeningToOnSwitchChange = true;
}
mSwitchWidget.setupView();
}
public void teardownSwitchController() {
if (mListeningToOnSwitchChange) {
mSwitchWidget.stopListening();
mListeningToOnSwitchChange = false;
}
mSwitchWidget.teardownView();
}
public void resume(Context context) {
mContext = context;
// Wi-Fi state is sticky, so just let the receiver update UI
mContext.registerReceiver(mReceiver, mIntentFilter);
if (!mListeningToOnSwitchChange) {
mSwitchWidget.startListening();
mListeningToOnSwitchChange = true;
}
}
public void pause() {
mContext.unregisterReceiver(mReceiver);
if (mListeningToOnSwitchChange) {
mSwitchWidget.stopListening();
mListeningToOnSwitchChange = false;
}
}
private void handleWifiStateChanged(int state) {
// Clear any previous state
mSwitchWidget.setDisabledByAdmin(null);
switch (state) {
case WifiManager.WIFI_STATE_ENABLING:
break;
case WifiManager.WIFI_STATE_ENABLED:
setSwitchBarChecked(true);
mSwitchWidget.setEnabled(true);
break;
case WifiManager.WIFI_STATE_DISABLING:
break;
case WifiManager.WIFI_STATE_DISABLED:
setSwitchBarChecked(false);
mSwitchWidget.setEnabled(true);
break;
default:
setSwitchBarChecked(false);
mSwitchWidget.setEnabled(true);
}
if (mayDisableTethering(!mSwitchWidget.isChecked())) {
if (RestrictedLockUtils.hasBaseUserRestriction(mContext,
UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
mSwitchWidget.setEnabled(false);
} else {
final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
mSwitchWidget.setDisabledByAdmin(admin);
}
}
}
private void setSwitchBarChecked(boolean checked) {
mStateMachineEvent = true;
mSwitchWidget.setChecked(checked);
mStateMachineEvent = false;
}
private void handleStateChanged(@SuppressWarnings("unused") NetworkInfo.DetailedState state) {
// After the refactoring from a CheckBoxPreference to a Switch, this method is useless since
// there is nowhere to display a summary.
// This code is kept in case a future change re-introduces an associated text.
/*
// WifiInfo is valid if and only if Wi-Fi is enabled.
// Here we use the state of the switch as an optimization.
if (state != null && mSwitch.isChecked()) {
WifiInfo info = mWifiManager.getConnectionInfo();
if (info != null) {
//setSummary(Summary.get(mContext, info.getSSID(), state));
}
}
*/
}
@Override
public boolean onSwitchToggled(boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return true;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listenenr loop.
mSwitchWidget.setChecked(false);
return false;
}
// Disable tethering if enabling Wifi
if (mayDisableTethering(isChecked)) {
mWifiManager.setWifiApEnabled(null, false);
}
if (isChecked) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
} else {
// Log if user was connected at the time of switching off.
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
mConnected.get());
}
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitchWidget.setEnabled(true);
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
return true;
}
private boolean mayDisableTethering(boolean isChecked) {
final int wifiApState = mWifiManager.getWifiApState();
return isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED));
}
}