Merge "Refactor hotspot into a full page"

This commit is contained in:
TreeHugger Robot
2017-06-14 21:33:19 +00:00
committed by Android (Google) Code Review
25 changed files with 1820 additions and 18 deletions

View File

@@ -43,6 +43,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.wifi.WifiApDialog;
import com.android.settings.wifi.WifiApEnabler;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
import com.android.settings.wifi.tether.WifiTetherSettings;
import com.android.settingslib.TetherUtil;
import java.lang.ref.WeakReference;
@@ -63,7 +65,6 @@ public class TetherSettings extends RestrictedSettingsFragment
private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
private static final String ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering";
private static final String TETHER_CHOICE = "TETHER_TYPE";
private static final String DATA_SAVER_FOOTER = "disabled_on_data_saver";
private static final int DIALOG_AP_SETTINGS = 1;
@@ -100,17 +101,14 @@ public class TetherSettings extends RestrictedSettingsFragment
private WifiConfiguration mWifiConfig = null;
private ConnectivityManager mCm;
private WifiTetherPreferenceController mWifiTetherPreferenceController;
private boolean mRestartWifiApAfterConfigChange;
private boolean mUsbConnected;
private boolean mMassStorageActive;
private boolean mBluetoothEnableForTether;
/* Stores the package name and the class name of the provisioning app */
private String[] mProvisionApp;
private static final int PROVISION_REQUEST = 0;
private boolean mUnavailable;
private DataSaverBackend mDataSaverBackend;
@@ -126,6 +124,13 @@ public class TetherSettings extends RestrictedSettingsFragment
super(UserManager.DISALLOW_CONFIG_TETHERING);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mWifiTetherPreferenceController =
new WifiTetherPreferenceController(context, getLifecycle());
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -154,6 +159,7 @@ public class TetherSettings extends RestrictedSettingsFragment
mEnableWifiAp =
(SwitchPreference) findPreference(ENABLE_WIFI_AP);
Preference wifiApSettings = findPreference(WIFI_AP_SSID_AND_SECURITY);
mUsbTether = (SwitchPreference) findPreference(USB_TETHER_SETTINGS);
mBluetoothTether = (SwitchPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
@@ -175,12 +181,18 @@ public class TetherSettings extends RestrictedSettingsFragment
getPreferenceScreen().removePreference(mUsbTether);
}
if (wifiAvailable && !Utils.isMonkeyRunning()) {
mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);
initWifiTethering();
mWifiTetherPreferenceController.displayPreference(getPreferenceScreen());
if (WifiTetherSettings.isTetherSettingPageEnabled()) {
removePreference(ENABLE_WIFI_AP);
removePreference(WIFI_AP_SSID_AND_SECURITY);
} else {
getPreferenceScreen().removePreference(mEnableWifiAp);
getPreferenceScreen().removePreference(wifiApSettings);
if (wifiAvailable && !Utils.isMonkeyRunning()) {
mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);
initWifiTethering();
} else {
getPreferenceScreen().removePreference(mEnableWifiAp);
getPreferenceScreen().removePreference(wifiApSettings);
}
}
if (!bluetoothAvailable) {

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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.widget;
import android.app.AlertDialog;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import com.android.settings.CustomEditTextPreference;
/**
* {@code EditTextPreference} that supports input validation.
*/
public class ValidatedEditTextPreference extends CustomEditTextPreference {
public interface Validator {
boolean isTextValid(String value);
}
private final EditTextWatcher mTextWatcher = new EditTextWatcher();
private Validator mValidator;
private boolean mIsPassword;
public ValidatedEditTextPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ValidatedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ValidatedEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ValidatedEditTextPreference(Context context) {
super(context);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
if (mValidator != null) {
final EditText editText = view.findViewById(android.R.id.edit);
if (editText != null) {
editText.removeTextChangedListener(mTextWatcher);
if (mIsPassword) {
editText.setInputType(
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
editText.setMaxLines(1);
}
editText.addTextChangedListener(mTextWatcher);
}
}
}
public void setIsPassword(boolean isPassword) {
mIsPassword = isPassword;
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public boolean isPassword() {
return mIsPassword;
}
public void setValidator(Validator validator) {
mValidator = validator;
}
private class EditTextWatcher implements TextWatcher {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
final EditText editText = getEditText();
if (mValidator != null && editText != null) {
final AlertDialog dialog = (AlertDialog) getDialog();
final boolean valid = mValidator.isTextValid(editText.getText().toString());
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(valid);
}
}
}
}

View File

@@ -32,6 +32,10 @@ import com.android.settings.datausage.DataSaverBackend;
import java.util.ArrayList;
/**
* @deprecated in favor of WifiTetherPreferenceController and WifiTetherSettings
*/
@Deprecated
public class WifiApEnabler {
private final Context mContext;
private final SwitchPreference mSwitch;

View File

@@ -110,7 +110,6 @@ public class WifiConfigController implements TextWatcher,
public static final int WIFI_PEAP_PHASE2_AKA = 4;
public static final int WIFI_PEAP_PHASE2_AKA_PRIME = 5;
private static final int SSID_ASCII_MAX_LENGTH = 32;
/* Phase2 methods supported by PEAP are limited */
private final ArrayAdapter<String> mPhase2PeapAdapter;
@@ -463,7 +462,7 @@ public class WifiConfigController implements TextWatcher,
if (mSsidView != null) {
final String ssid = mSsidView.getText().toString();
if (ssid.length() > SSID_ASCII_MAX_LENGTH) {
if (WifiUtils.isSSIDTooLong(ssid)) {
mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2017 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.text.TextUtils;
public class WifiUtils {
private static final int SSID_ASCII_MIN_LENGTH = 1;
private static final int SSID_ASCII_MAX_LENGTH = 32;
private static final int PASSWORD_MIN_LENGTH = 8;
private static final int PASSWORD_MAX_LENGTH = 63;
public static boolean isSSIDTooLong(String ssid) {
if (TextUtils.isEmpty(ssid)) {
return false;
}
return ssid.length() > SSID_ASCII_MAX_LENGTH;
}
public static boolean isSSIDTooShort(String ssid) {
if (TextUtils.isEmpty(ssid)) {
return true;
}
return ssid.length() < SSID_ASCII_MIN_LENGTH;
}
public static boolean isPasswordValid(String password) {
if (TextUtils.isEmpty(password)) {
return false;
}
final int length = password.length();
return length >= PASSWORD_MIN_LENGTH && length <= PASSWORD_MAX_LENGTH;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2017 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.tether;
import android.net.ConnectivityManager;
class NoOpOnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback {
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import static android.net.wifi.WifiConfiguration.AP_BAND_2GHZ;
import static android.net.wifi.WifiConfiguration.AP_BAND_5GHZ;
public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferenceController {
private static final String PREF_KEY = "wifi_tether_network_ap_band";
private static final String[] BAND_VALUES =
{String.valueOf(AP_BAND_2GHZ), String.valueOf(AP_BAND_5GHZ)};
private final String[] mBandEntries;
private int mBandIndex;
public WifiTetherApBandPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
mBandEntries = mContext.getResources().getStringArray(R.array.wifi_ap_band_config_full);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mBandIndex = config.apBand;
} else {
mBandIndex = 0;
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
ListPreference preference = (ListPreference) mPreference;
if (!is5GhzBandSupported()) {
preference.setEnabled(false);
preference.setSummary(R.string.wifi_ap_choose_2G);
} else {
preference.setEntries(mBandEntries);
preference.setEntryValues(BAND_VALUES);
preference.setSummary(mBandEntries[mBandIndex]);
preference.setValue(String.valueOf(mBandIndex));
}
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mBandIndex = Integer.parseInt((String) newValue);
preference.setSummary(mBandEntries[mBandIndex]);
mListener.onTetherConfigUpdated();
return true;
}
private boolean is5GhzBandSupported() {
if (mBandIndex > 0) {
return true;
}
return mWifiManager.is5GHzBandSupported();
}
public int getBandIndex() {
return mBandIndex;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceController;
public abstract class WifiTetherBasePreferenceController extends PreferenceController
implements Preference.OnPreferenceChangeListener {
public interface OnTetherConfigUpdateListener {
void onTetherConfigUpdated();
}
protected final WifiManager mWifiManager;
protected final String[] mWifiRegexs;
protected final ConnectivityManager mCm;
protected final OnTetherConfigUpdateListener mListener;
protected Preference mPreference;
public WifiTetherBasePreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context);
mListener = listener;
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiRegexs = mCm.getTetherableWifiRegexs();
}
@Override
public boolean isAvailable() {
return mWifiManager != null && mWifiRegexs != null && mWifiRegexs.length > 0;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settings.wifi.WifiUtils;
public class WifiTetherPasswordPreferenceController extends WifiTetherBasePreferenceController
implements ValidatedEditTextPreference.Validator {
private static final String PREF_KEY = "wifi_tether_network_password";
private String mPassword;
public WifiTetherPasswordPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mPassword = config.preSharedKey;
}
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
((ValidatedEditTextPreference) mPreference).setText(mPassword);
((ValidatedEditTextPreference) mPreference).setIsPassword(true);
((ValidatedEditTextPreference) mPreference).setValidator(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mPassword = (String) newValue;
((ValidatedEditTextPreference) mPreference).setText(mPassword);
mListener.onTetherConfigUpdated();
return true;
}
public String getPassword() {
return mPassword;
}
@Override
public boolean isTextValid(String value) {
return WifiUtils.isPasswordValid(value);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.BidiFormatter;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.List;
public class WifiTetherPreferenceController extends PreferenceController
implements LifecycleObserver, OnResume, OnPause {
public static final IntentFilter WIFI_TETHER_INTENT_FILTER;
private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
private final ConnectivityManager mConnectivityManager;
private final String[] mWifiRegexs;
private final WifiManager mWifiManager;
private Preference mPreference;
static {
WIFI_TETHER_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
WIFI_TETHER_INTENT_FILTER.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
WIFI_TETHER_INTENT_FILTER.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
}
public WifiTetherPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mWifiRegexs = mConnectivityManager.getTetherableWifiRegexs();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
return mWifiRegexs != null
&& mWifiRegexs.length != 0
&& WifiTetherSettings.isTetherSettingPageEnabled()
&& !Utils.isMonkeyRunning();
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(WIFI_TETHER_SETTINGS);
}
@Override
public String getPreferenceKey() {
return WIFI_TETHER_SETTINGS;
}
@Override
public void onResume() {
if (mPreference != null) {
mContext.registerReceiver(mReceiver, WIFI_TETHER_INTENT_FILTER);
clearSummaryForAirplaneMode();
}
}
@Override
public void onPause() {
if (mPreference != null) {
mContext.unregisterReceiver(mReceiver);
}
}
//
// Everything below is copied from WifiApEnabler
//
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
int reason = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON,
WifiManager.SAP_START_FAILURE_GENERAL);
handleWifiApStateChanged(state, reason);
} else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
List<String> active = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ACTIVE_TETHER);
List<String> errored = intent.getStringArrayListExtra(
ConnectivityManager.EXTRA_ERRORED_TETHER);
updateTetherState(active.toArray(), errored.toArray());
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
clearSummaryForAirplaneMode();
}
}
};
private void handleWifiApStateChanged(int state, int reason) {
switch (state) {
case WifiManager.WIFI_AP_STATE_ENABLED:
/**
* Summary on enable is handled by tether
* broadcast notice
*/
break;
case WifiManager.WIFI_AP_STATE_DISABLING:
mPreference.setSummary(R.string.wifi_tether_stopping);
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
clearSummaryForAirplaneMode();
break;
default:
if (reason == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
mPreference.setSummary(R.string.wifi_sap_no_channel_error);
} else {
mPreference.setSummary(R.string.wifi_error);
}
clearSummaryForAirplaneMode();
}
}
private void updateTetherState(Object[] tethered, Object[] errored) {
boolean wifiTethered = matchRegex(tethered);
boolean wifiErrored = matchRegex(errored);
if (wifiTethered) {
WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
updateConfigSummary(wifiConfig);
} else if (wifiErrored) {
mPreference.setSummary(R.string.wifi_error);
} else {
mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
}
}
private boolean matchRegex(Object[] tethers) {
for (Object o : tethers) {
String s = (String) o;
for (String regex : mWifiRegexs) {
if (s.matches(regex)) {
return true;
}
}
}
return false;
}
private void updateConfigSummary(WifiConfiguration wifiConfig) {
final String s = mContext.getString(
com.android.internal.R.string.wifi_tether_configure_ssid_default);
mPreference.setSummary(mContext.getString(R.string.wifi_tether_enabled_subtext,
BidiFormatter.getInstance().unicodeWrap(
(wifiConfig == null) ? s : wifiConfig.SSID)));
}
private void clearSummaryForAirplaneMode() {
boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
if (isAirplaneMode) {
mPreference.setSummary(R.string.summary_placeholder);
}
}
//
// Everything above is copied from WifiApEnabler
//
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settings.wifi.WifiUtils;
public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController
implements ValidatedEditTextPreference.Validator {
private static final String PREF_KEY = "wifi_tether_network_name";
@VisibleForTesting
static final String DEFAULT_SSID = "AndroidAP";
private String mSSID;
public WifiTetherSSIDPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
}
@Override
public String getPreferenceKey() {
return PREF_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mSSID = config.SSID;
} else {
mSSID = DEFAULT_SSID;
}
((ValidatedEditTextPreference) mPreference).setValidator(this);
updateSsidDisplay((EditTextPreference) mPreference);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSSID = (String) newValue;
updateSsidDisplay((EditTextPreference) preference);
mListener.onTetherConfigUpdated();
return true;
}
@Override
public boolean isTextValid(String value) {
return !WifiUtils.isSSIDTooLong(value) && !WifiUtils.isSSIDTooShort(value);
}
public String getSSID() {
return mSSID;
}
private void updateSsidDisplay(EditTextPreference preference) {
preference.setText(mSSID);
preference.setSummary(mSSID);
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.SystemProperties;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.widget.SwitchBar;
import java.util.ArrayList;
import java.util.List;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
public class WifiTetherSettings extends RestrictedDashboardFragment
implements WifiTetherBasePreferenceController.OnTetherConfigUpdateListener {
public static boolean isTetherSettingPageEnabled() {
return SystemProperties.getBoolean("settings.ui.wifi.tether.enabled", true);
}
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
private WifiTetherApBandPreferenceController mApBandPreferenceController;
private WifiManager mWifiManager;
private boolean mRestartWifiApAfterConfigChange;
@VisibleForTesting
TetherChangeReceiver mTetherChangeReceiver;
static {
TETHER_STATE_CHANGE_FILTER = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
TETHER_STATE_CHANGE_FILTER.addAction(WIFI_AP_STATE_CHANGED_ACTION);
}
public WifiTetherSettings() {
super(UserManager.DISALLOW_CONFIG_TETHERING);
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.WIFI_TETHER_SETTINGS;
}
@Override
protected String getLogTag() {
return "WifiTetherSettings";
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mTetherChangeReceiver = new TetherChangeReceiver();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Assume we are in a SettingsActivity. This is only safe because we currently use
// SettingsActivity as base for all preference fragments.
final SettingsActivity activity = (SettingsActivity) getActivity();
final SwitchBar switchBar = activity.getSwitchBar();
mSwitchBarController = new WifiTetherSwitchBarController(activity, switchBar);
getLifecycle().addObserver(mSwitchBarController);
switchBar.show();
}
@Override
public void onStart() {
super.onStart();
final Context context = getContext();
if (context != null) {
context.registerReceiver(mTetherChangeReceiver, TETHER_STATE_CHANGE_FILTER);
}
}
@Override
public void onStop() {
super.onStop();
final Context context = getContext();
if (context != null) {
context.unregisterReceiver(mTetherChangeReceiver);
}
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.wifi_tether_settings;
}
@Override
protected List<PreferenceController> getPreferenceControllers(Context context) {
final List<PreferenceController> controllers = new ArrayList<>();
mSSIDPreferenceController = new WifiTetherSSIDPreferenceController(context, this);
mPasswordPreferenceController = new WifiTetherPasswordPreferenceController(context, this);
mApBandPreferenceController = new WifiTetherApBandPreferenceController(context, this);
controllers.add(mSSIDPreferenceController);
controllers.add(mPasswordPreferenceController);
controllers.add(mApBandPreferenceController);
return controllers;
}
@Override
public void onTetherConfigUpdated() {
final WifiConfiguration config = buildNewConfig();
/**
* if soft AP is stopped, bring up
* else restart with new config
* TODO: update config on a running access point when framework support is added
*/
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
Log.d("TetheringSettings",
"Wifi AP config changed while enabled, stop and restart");
mRestartWifiApAfterConfigChange = true;
mSwitchBarController.stopTether();
}
mWifiManager.setWifiApConfiguration(config);
}
private WifiConfiguration buildNewConfig() {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = mSSIDPreferenceController.getSSID();
config.preSharedKey = mPasswordPreferenceController.getPassword();
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.apBand = mApBandPreferenceController.getBandIndex();
return config;
}
@VisibleForTesting
class TetherChangeReceiver extends BroadcastReceiver {
private static final String TAG = "TetherChangeReceiver";
@Override
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_TETHER_STATE_CHANGED)) {
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
mSwitchBarController.startTether();
}
} else if (action.equals(WIFI_AP_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
if (state == WifiManager.WIFI_AP_STATE_DISABLED
&& mRestartWifiApAfterConfigChange) {
mRestartWifiApAfterConfigChange = false;
Log.d(TAG, "Restarting WifiAp due to prior config change.");
mSwitchBarController.startTether();
}
}
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2017 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.tether;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.widget.Switch;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import static android.net.ConnectivityManager.TETHERING_WIFI;
public class WifiTetherSwitchBarController implements SwitchBar.OnSwitchChangeListener,
LifecycleObserver, OnStart, OnStop {
private final Context mContext;
private final SwitchBar mSwitchBar;
private final ConnectivityManager mConnectivityManager;
private final DataSaverBackend mDataSaverBackend;
private final NoOpOnStartTetheringCallback mOnStartTetheringCallback;
WifiTetherSwitchBarController(Context context, SwitchBar switchBar) {
mContext = context;
mSwitchBar = switchBar;
mDataSaverBackend = new DataSaverBackend(context);
mOnStartTetheringCallback = new NoOpOnStartTetheringCallback();
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mSwitchBar.addOnSwitchChangeListener(this);
}
@Override
public void onStart() {
mContext.registerReceiver(mReceiver,
WifiTetherPreferenceController.WIFI_TETHER_INTENT_FILTER);
}
@Override
public void onStop() {
mContext.unregisterReceiver(mReceiver);
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (isChecked) {
startTether();
} else {
stopTether();
}
}
void stopTether() {
mSwitchBar.setEnabled(false);
mConnectivityManager.stopTethering(TETHERING_WIFI);
}
void startTether() {
mSwitchBar.setEnabled(false);
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
final int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
handleWifiApStateChanged(state);
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
enableWifiSwitch();
}
}
};
private void handleWifiApStateChanged(int state) {
switch (state) {
case WifiManager.WIFI_AP_STATE_ENABLING:
mSwitchBar.setEnabled(false);
break;
case WifiManager.WIFI_AP_STATE_ENABLED:
if (!mSwitchBar.isChecked()) {
mSwitchBar.setChecked(true);
}
enableWifiSwitch();
break;
case WifiManager.WIFI_AP_STATE_DISABLING:
if (mSwitchBar.isChecked()) {
mSwitchBar.setChecked(false);
}
mSwitchBar.setEnabled(false);
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
mSwitchBar.setChecked(false);
enableWifiSwitch();
break;
default:
mSwitchBar.setChecked(false);
enableWifiSwitch();
break;
}
}
private void enableWifiSwitch() {
boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
if (!isAirplaneMode) {
mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
} else {
mSwitchBar.setEnabled(false);
}
}
}